Start · Sprachen · JavaScript · Referenz · AudioWorkletGlobalScope.currentTime

AudioWorkletGlobalScope.currentTime

Eigenschaft

Liefert die ständig steigende Kontextzeit in Sekunden für den Audioblock, der gerade im AudioWorklet verarbeitet wird. Die Eigenschaft ist schreibgeschützt.

seit JavaScript Baseline: alle modernen Browser (Chrome 66+, Firef Kategorie: webapi

Signatur

AudioWorkletGlobalScope.currentTime

Beschreibung

currentTime ist eine globale, schreibgeschützte Eigenschaft im Scope eines AudioWorklets. Sie gibt einen number-Wert (Double) in Sekunden zurück. Dieser Wert entspricht der Kontextzeit des Audioblocks, den die Engine gerade verarbeitet. Er entspricht BaseAudioContext.currentTime im Hauptthread, wird aber direkt im Audio-Rendering-Thread gelesen und ist deshalb für diesen Block exakt.

Weil der Code eines AudioWorkletProcessor im globalen Scope des Worklets läuft, greifst du einfach über den Bezeichner currentTime darauf zu. Ein Präfix wie globalThis ist nicht nötig. Die Zeit springt pro Aufruf von process() um genau 128 / sampleRate Sekunden weiter, also um eine Blocklänge (render quantum). Innerhalb eines Blocks bleibt sie gleich.

Typische Anwendungen:

  • sample-genaues Planen von Ereignissen, z. B. Hüllkurven, Metronom-Klicks oder das Ein- und Ausschalten eines Oszillators zu einem bestimmten Zeitpunkt,
  • Abgleich mit Zeitstempeln, die der Hauptthread per port.postMessage() schickt,
  • Messungen und Diagnose im Rendering-Thread.

Wenn du die Zeit eines einzelnen Samples innerhalb des Blocks brauchst, rechne sie selbst aus: currentTime + i / sampleRate. Alternativ kannst du mit currentFrame arbeiten.

Rückgabewert

Typ
number
Beschreibung
Die Kontextzeit des aktuell verarbeiteten Audioblocks in Sekunden (Double, ≥ 0). Sie steigt monoton an.

Beispiele

Kontextzeit im Prozessor auslesen

// time-logger.js (wird per audioWorklet.addModule geladen)
class TimeLogger extends AudioWorkletProcessor {
  constructor() {
    super();
    this.lastLog = 0;
  }

  process() {
    // Etwa einmal pro Sekunde die Zeit an den Hauptthread melden
    if (currentTime - this.lastLog >= 1) {
      this.lastLog = currentTime;
      this.port.postMessage({ time: currentTime, frame: currentFrame });
    }
    return true;
  }
}

registerProcessor('time-logger', TimeLogger);

// main.js
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('time-logger.js');
const node = new AudioWorkletNode(ctx, 'time-logger');
node.port.onmessage = ({ data }) => console.log(data);
node.connect(ctx.destination);
{ time: 1.0026666666666666, frame: 48128 } { time: 2.0026666666666666, frame: 96128 }

Sample-genaues Ein- und Ausschalten eines Tons

// gated-sine.js
class GatedSine extends AudioWorkletProcessor {
  constructor() {
    super();
    this.phase = 0;
    this.start = Infinity;
    this.stop = Infinity;
    // Hauptthread schickt Start- und Stoppzeit in Kontextzeit
    this.port.onmessage = ({ data }) => {
      this.start = data.start;
      this.stop = data.stop;
    };
  }

  process(inputs, outputs) {
    const out = outputs[0][0];
    for (let i = 0; i < out.length; i++) {
      const t = currentTime + i / sampleRate; // Zeit dieses Samples
      const active = t >= this.start && t < this.stop;
      out[i] = active ? Math.sin(this.phase) * 0.2 : 0;
      this.phase += (2 * Math.PI * 440) / sampleRate;
    }
    return true;
  }
}

registerProcessor('gated-sine', GatedSine);

// main.js
const ctx = new AudioContext();
await ctx.audioWorklet.addModule('gated-sine.js');
const sine = new AudioWorkletNode(ctx, 'gated-sine');
sine.connect(ctx.destination);
const now = ctx.currentTime;
sine.port.postMessage({ start: now + 0.5, stop: now + 1.5 });

Blockdauer aus currentTime ableiten

// block-check.js
class BlockCheck extends AudioWorkletProcessor {
  constructor() {
    super();
    this.prev = null;
  }

  process() {
    if (this.prev !== null) {
      const delta = currentTime - this.prev;
      // Entspricht 128 / sampleRate
      this.port.postMessage({ delta, expected: 128 / sampleRate });
      return false; // Prozessor danach beenden
    }
    this.prev = currentTime;
    return true;
  }
}

registerProcessor('block-check', BlockCheck);
{ delta: 0.0026666666666666666, expected: 0.0026666666666666666 }

// Wichtig · Fallstricke

  • Nur im Worklet verfügbar: currentTime gibt es ausschließlich im AudioWorkletGlobalScope. Im Hauptthread verwendest du stattdessen audioContext.currentTime.
  • Schreibgeschützt: Eine Zuweisung hat keine Wirkung. Im Strict Mode, der in ES-Modulen immer gilt, löst sie einen TypeError aus. Lege außerdem keine eigene Variable mit dem Namen currentTime an, denn sie würde die globale Eigenschaft verdecken.
  • Auflösung pro Block: Der Wert ändert sich nur einmal pro Render-Quantum, normalerweise alle 128 Frames. Für eine Genauigkeit auf Sample-Ebene rechnest du currentTime + i / sampleRate.
  • Keine Wanduhr: Die Kontextzeit bleibt stehen, solange der AudioContext angehalten ist (suspend()). Sie hängt nicht mit performance.now() oder Date.now() zusammen. Zum Umrechnen dient AudioContext.getOutputTimestamp() im Hauptthread.
  • Latenz bei Nachrichten: Zeitwerte, die per postMessage ankommen, können schon in der Vergangenheit liegen. Plane deshalb mit etwas Vorlauf, z. B. ctx.currentTime + 0.1.
  • Kompatibilität: AudioWorklet setzt einen sicheren Kontext (HTTPS) voraus. Unterstützt wird es in Chrome/Edge 66+, Firefox 76+ und Safari 14.1+.