Signatur
Beschreibung
Die Eigenschaft playbackTime eines AudioProcessingEvent enthält einen double-Wert in Sekunden. Er gibt an, wann der Audioblock, den du gerade im audioprocess-Handler eines ScriptProcessorNode in outputBuffer schreibst, tatsächlich hörbar wird. Die Zeitachse ist dieselbe wie bei AudioContext.currentTime.
Weil ein ScriptProcessorNode Daten blockweise und mit Pufferlatenz verarbeitet, liegt playbackTime in der Regel etwas nach dem aktuellen currentTime. Den Wert kannst du nutzen, um eigene Klangerzeugung zeitlich genau zu steuern, etwa bei einem Metronom, einem Sequenzer oder einer Hüllkurve, die an geplante Ereignisse gekoppelt ist.
Die Eigenschaft ist schreibgeschützt und gilt nur für das jeweilige Ereignisobjekt. Zusammen mit inputBuffer.length und sampleRate kannst du für jedes einzelne Sample die genaue Abspielzeit berechnen: playbackTime + i / sampleRate.
Rückgabewert
double in Sekunden auf der Zeitachse des zugehörigen AudioContext. Er gibt an, wann das erste Sample des aktuellen Blocks abgespielt wird.Beispiele
Abspielzeit und Latenz protokollieren
const ctx = new AudioContext();
const processor = ctx.createScriptProcessor(4096, 1, 1);
processor.addEventListener('audioprocess', (event) => {
const latency = event.playbackTime - ctx.currentTime;
console.log(`Block spielt bei ${event.playbackTime.toFixed(3)} s (Latenz ≈ ${(latency * 1000).toFixed(1)} ms)`);
// Eingang unverändert durchreichen
event.outputBuffer.getChannelData(0).set(event.inputBuffer.getChannelData(0));
});
processor.connect(ctx.destination);
Sinuston zeitgenau (phasenkontinuierlich) erzeugen
const ctx = new AudioContext();
const processor = ctx.createScriptProcessor(2048, 0, 1);
const freq = 440;
processor.onaudioprocess = (event) => {
const out = event.outputBuffer.getChannelData(0);
const sr = ctx.sampleRate;
for (let i = 0; i < out.length; i++) {
// Absolute Zeit jedes Samples
const t = event.playbackTime + i / sr;
out[i] = 0.2 * Math.sin(2 * Math.PI * freq * t);
}
};
processor.connect(ctx.destination);
Metronom-Klick zu geplanten Zeitpunkten
const ctx = new AudioContext();
const processor = ctx.createScriptProcessor(1024, 0, 1);
const interval = 0.5; // 120 BPM
const clickLen = 0.01;
processor.onaudioprocess = ({ playbackTime, outputBuffer }) => {
const out = outputBuffer.getChannelData(0);
const sr = ctx.sampleRate;
for (let i = 0; i < out.length; i++) {
const t = playbackTime + i / sr;
const phase = t % interval;
out[i] = phase < clickLen ? (Math.random() * 2 - 1) * 0.5 : 0;
}
};
processor.connect(ctx.destination);
// Wichtig · Fallstricke
- Veraltet:
AudioProcessingEventundScriptProcessorNodesind in der Web-Audio-Spezifikation als veraltet markiert. Nutze für neue ProjekteAudioWorkletNodebzw.AudioWorkletProcessor. Dort liefern die globalen WertecurrentTimeundcurrentFrameimAudioWorkletGlobalScopedie entsprechenden Zeitinformationen. - Der Handler läuft im Haupt-Thread. Wenn die Seite ausgelastet ist, kommt es zu Aussetzern, und
playbackTimekann zwischen zwei Aufrufen um mehr als eine Blocklänge springen. - Leite die Phase von Oszillatoren aus
playbackTimeab statt aus einem eigenen Zähler. So bleibt die Synchronisation mit anderen Knoten erhalten, die überstart(when)geplant sind. - Die Browser setzen den Wert unterschiedlich genau um. In älteren Safari-Versionen (nur
webkitAudioContext) istplaybackTimeteilweise ungenau oder nicht vorhanden. Prüfe daher mittypeof event.playbackTime === 'number'. - Auf
playbackTimekommt es erst an, wenn der Kontext läuft. Wegen der Autoplay-Richtlinien musst ductx.resume()meist nach einer Nutzeraktion aufrufen.