Start · Sprachen · JavaScript · Referenz · AudioWorkletGlobalScope.currentFrame

AudioWorkletGlobalScope.currentFrame

Eigenschaft

Liefert als schreibgeschützte Ganzzahl den stetig wachsenden Sample-Frame des Audio-Blocks, der gerade verarbeitet wird – nur im AudioWorklet-Kontext verfügbar.

seit JavaScript Baseline: alle modernen Browser (seit 2021) Kategorie: webapi

Signatur

AudioWorkletGlobalScope.currentFrame

Beschreibung

currentFrame ist eine globale, schreibgeschützte Eigenschaft innerhalb des AudioWorkletGlobalScope, also in dem Skript, das Sie per audioContext.audioWorklet.addModule() laden. Sie gibt den Index des ersten Sample-Frames des Audio-Blocks an, der gerade verarbeitet wird. Der Wert beginnt bei 0, wenn der Kontext startet, und wächst mit jedem sogenannten Render-Quantum (in der Regel 128 Frames) weiter.

Die Eigenschaft ist das Gegenstück zu currentTime, allerdings in Samples statt in Sekunden: Es gilt currentTime === currentFrame / sampleRate. Weil der Wert eine Ganzzahl ist, eignet er sich besonders für sample-genaues Timing, etwa für Metronome, Sequenzer, das Planen von Ereignissen auf ein bestimmtes Sample oder das Messen von Zeitabständen ohne Rundungsfehler durch Gleitkommazahlen.

Typischerweise liest man currentFrame in der Methode process() eines AudioWorkletProcessor. Da während der Verarbeitung eines Blocks alle Prozessoren denselben Wert sehen, eignet er sich auch zur Synchronisierung mehrerer Prozessoren im selben Kontext.

Rückgabewert

Typ
number
Beschreibung
Eine nicht negative Ganzzahl: der Index des ersten Sample-Frames im aktuell verarbeiteten Audio-Block. Sie wächst pro Aufruf von process() um die Blockgröße (meist 128).

Beispiele

currentFrame in process() auslesen und an den Haupt-Thread melden

// frame-logger.js (AudioWorklet-Modul)
class FrameLogger extends AudioWorkletProcessor {
  constructor() {
    super();
    this.lastReport = 0;
  }

  process(inputs, outputs) {
    // Etwa einmal pro Sekunde melden
    if (currentFrame - this.lastReport >= sampleRate) {
      this.lastReport = currentFrame;
      this.port.postMessage({ frame: currentFrame, time: currentTime });
    }
    return true;
  }
}

registerProcessor('frame-logger', FrameLogger);

// main.js (Haupt-Thread)
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('frame-logger.js');
const node = new AudioWorkletNode(ctx, 'frame-logger');
node.port.onmessage = ({ data }) => console.log(data);
node.connect(ctx.destination);
{ frame: 48000, time: 1 } { frame: 96000, time: 2 }

Sample-genaues Metronom (Klick jede halbe Sekunde)

// metronome.js
class Metronome extends AudioWorkletProcessor {
  constructor() {
    super();
    this.interval = Math.round(sampleRate * 0.5); // 0,5 s in Frames
    this.clickLength = 200;
  }

  process(inputs, outputs) {
    const channel = outputs[0][0];
    for (let i = 0; i < channel.length; i++) {
      const frame = currentFrame + i; // absoluter Frame-Index des Samples
      const pos = frame % this.interval;
      channel[i] = pos < this.clickLength
        ? Math.sin(2 * Math.PI * 1000 * pos / sampleRate) * 0.5
        : 0;
    }
    return true;
  }
}

registerProcessor('metronome', Metronome);

Ereignis auf einen bestimmten Frame planen

// scheduler.js
class Scheduler extends AudioWorkletProcessor {
  constructor() {
    super();
    this.targetFrame = null;
    this.port.onmessage = ({ data }) => {
      // Sekunden (AudioContext.currentTime-Basis) in Frames umrechnen
      this.targetFrame = Math.round(data.at * sampleRate);
    };
  }

  process(inputs, outputs) {
    const blockSize = outputs[0][0].length;
    if (this.targetFrame !== null &&
        this.targetFrame >= currentFrame &&
        this.targetFrame < currentFrame + blockSize) {
      const offset = this.targetFrame - currentFrame;
      this.port.postMessage(`Ereignis in Block ab ${currentFrame}, Offset ${offset}`);
      this.targetFrame = null;
    }
    return true;
  }
}

registerProcessor('scheduler', Scheduler);

// main.js
// node.port.postMessage({ at: ctx.currentTime + 2 });
Ereignis in Block ab 95872, Offset 128

// Wichtig · Fallstricke

  • Nur im AudioWorklet-Kontext: currentFrame existiert ausschließlich im AudioWorkletGlobalScope. Im Haupt-Thread gibt es dafür keine Entsprechung; dort verwenden Sie AudioContext.currentTime und rechnen mit sampleRate um.
  • Block-Granularität: Der Wert bezeichnet nur den ersten Frame des aktuellen Blocks. Für das einzelne Sample innerhalb von process() addieren Sie den Schleifenindex (currentFrame + i).
  • Blockgröße nicht fest einprogrammieren: Nutzen Sie die Länge der Ausgabe-Arrays statt der Zahl 128 – künftige Versionen der Web Audio API sehen einstellbare Render-Quantum-Größen vor.
  • Angehaltener Kontext: Ist der AudioContext im Zustand suspended, wird process() nicht aufgerufen und currentFrame wächst nicht weiter.
  • Genauigkeit: Als Ganzzahl bleibt der Wert auch bei langen Laufzeiten exakt (sicher bis Number.MAX_SAFE_INTEGER), während Gleitkomma-Rechnungen mit currentTime Rundungsfehler ansammeln können.
  • Kompatibilität: Unterstützt in Chrome/Edge 66+, Firefox 76+ und Safari 14.1+. AudioWorklets setzen einen sicheren Kontext (HTTPS) voraus.