Zum Inhalt springen

Der Audio-Weg von Singler, vom AudioWorklet über den Web Worker bis zum Canvas, und die Filter, die entscheiden, ob du wirklich singst.

JP 2 Min. Lesezeit

Ein Gesangstrainer steht und fällt mit der Latenz. Hängt die Tonhöhenlinie hinter deiner Stimme her, jagst du der Linie hinterher statt dem Ton. Singler verarbeitet das gesamte Audio im Browser, auch auf dem Handy, und kein Audio verlässt je das Gerät. Die Pipeline muss also schnell sein und den Main-Thread in Ruhe lassen.

Drei Threads, jeder mit einer Aufgabe

Mikrofon → AudioWorklet (Samples sammeln)
         → Web Worker   (Tonhöhe erkennen, filtern, glätten)
         → Main-Thread  (zeichnen)

Das AudioWorklet läuft auf dem Audio-Thread und tut fast nichts: Es kopiert Samples in einen Puffer und überträgt ihn alle paar Millisekunden:

ts
process(inputs: Float32Array[][]): boolean {
  const channel = inputs[0]?.[0];
  if (!channel) return true;
  for (let i = 0; i < channel.length; i++) {
    this.buf[this.n++] = channel[i];
    if (this.n === this.hop) {
      (this.out ?? this.port).postMessage({ samples: this.buf, time: currentTime }, [this.buf.buffer]);
      this.buf = new Float32Array(this.hop);
      this.n = 0;
    }
  }
  return true;
}

Wichtig ist this.out: Beim Start erzeugt der Main-Thread einen MessageChannel und gibt ein Ende dem Worklet, das andere einem Web Worker. Die Samples gehen dann direkt vom Worklet zum Worker, und ein beschäftigter Main-Thread (Layout, Garbage Collection, langsames Handy) kann die Erkennung nicht verzögern.

Erst Tonhöhe, dann Urteil

Der Worker nutzt die McLeod Pitch Method über pitchy (MIT, klein, schnell). Sie liefert eine Frequenz und eine Klarheit zwischen 0 und 1. Diese rohe Schätzung muss noch geprüft werden, denn Atemgeräusche, ein Kühlschrank und der Referenzton aus dem Lautsprecher erzeugen alle „Tonhöhen“. Jeder Frame muss drei Filter passieren:

  1. Klarheit über einem Schwellwert: Ist das überhaupt periodisch?
  2. Pegel über dem Grundrauschen: Ein adaptiver Wert folgt dem Raum, bis das Mikrofon kalibriert ist, danach gilt der kalibrierte Wert.
  3. Bereich: Kann eine menschliche Stimme diese Frequenz erzeugen?

Was übrig bleibt, wird in MIDI-Werte umgerechnet und mit einem kurzen Median geglättet. Das entfernt Oktavsprünge ohne die Verzögerung eines langen Mittelwerts.

Halten ist etwas anderes als Anfangen

Wer einen Ton hält, wird gegen Ende natürlich leiser. Bliebe die Pegelschwelle fest, würde das Halten kurz vor einem guten Ende „abbrechen“. Deshalb lockert sich die Schwelle beim Halten um ein paar Dezibel. Eine Zeile Code, die die Halte-Übung fair gemacht hat.

Zeichnen im Takt des Bildschirms

Der Worker schickt etwa 90 Frames pro Sekunde. Das Canvas zeichnet per requestAnimationFrame, was seit dem letzten Bild angekommen ist. Rendern und Audio warten nie aufeinander. Die Erkennung hält ihr Tempo, egal was die Webseite gerade tut, und der Main-Thread bleibt frei für den Rest der Oberfläche.

#web-audio#performance#svelte

Über das Projekt

A4

breathe…

In Entwicklung

Singler

Online-Gesangstrainer mit Live-Feedback zur Tonhöhe.

Finde deinen Stimmumfang, triff Töne sauber und lerne, sie zu halten, mit Live-Feedback zur Tonhöhe. Läuft im Browser; dein Audio bleibt auf deinem Gerät.

Projekt ansehen →

Weiterlesen