Signatur
Beschreibung
Die Eigenschaft playbackRate eines AudioBufferSourceNode ist ein AudioParam, der festlegt, wie schnell der zugewiesene AudioBuffer abgespielt wird. Mit 1.0 läuft er in Originalgeschwindigkeit, 0.5 halbiert das Tempo, 2.0 verdoppelt es. Weil die Samples einfach schneller oder langsamer ausgelesen werden, ändert sich die Tonhöhe mit. Das klingt wie ein Tonband oder eine Schallplatte mit falscher Drehzahl. Eine Tonhöhenkorrektur wie bei HTMLMediaElement.preservesPitch gibt es nicht.
Die Eigenschaft selbst ist schreibgeschützt. Du änderst also nicht das Objekt, sondern seinen Wert, entweder direkt über playbackRate.value oder zeitgenau über die Automationsmethoden wie setValueAtTime(), linearRampToValueAtTime() oder setTargetAtTime(). Der Parameter ist k-rate: Sein Wert wird nur einmal pro Render-Block (128 Samples) ausgewertet, nicht für jedes einzelne Sample.
Zusammen mit detune ergibt sich die tatsächliche Rate: computedPlaybackRate = playbackRate * 2^(detune / 1200). Typische Einsatzfälle sind Sampler, bei denen ein einzelnes Sample in verschiedenen Tonhöhen gespielt wird, Effekte wie „Tape Stop“ oder „Vinyl Scratch“, Zeitlupen- und Zeitraffer-Effekte in Spielen und DJ-artige Pitch-Regler.
Rückgabewert
AudioParam mit defaultValue 1. Der Wertebereich reicht von der kleinsten bis zur größten 32-Bit-Gleitkommazahl (≈ -3.4028235e38 bis 3.4028235e38). automationRate ist fest auf "k-rate" eingestellt.Beispiele
Sample in halber Geschwindigkeit abspielen
const ctx = new AudioContext();
const playSlow = async (url) => {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
const source = ctx.createBufferSource();
source.buffer = audioBuffer;
source.playbackRate.value = 0.5; // halbes Tempo, eine Oktave tiefer
source.connect(ctx.destination);
source.start();
console.log(source.playbackRate.defaultValue, source.playbackRate.value);
};
document.querySelector('#play').addEventListener('click', () => {
ctx.resume();
playSlow('/audio/drum-loop.wav');
});
Sampler: gleiches Sample in verschiedenen Halbtönen
const ctx = new AudioContext();
// Halbtöne in Wiedergaberate umrechnen: 2^(n/12)
const semitonesToRate = (n) => 2 ** (n / 12);
const playNote = (buffer, semitones) => {
const source = new AudioBufferSourceNode(ctx, {
buffer,
playbackRate: semitonesToRate(semitones)
});
source.connect(ctx.destination);
source.start();
};
// Dur-Dreiklang aus einem einzigen Klavier-Sample (C)
const playChord = (pianoBuffer) => {
[0, 4, 7].forEach((n) => playNote(pianoBuffer, n));
console.log([0, 4, 7].map((n) => semitonesToRate(n).toFixed(3)));
};
„Tape Stop“-Effekt per Automation
const tapeStop = (source, ctx, duration = 1.5) => {
const now = ctx.currentTime;
const rate = source.playbackRate;
// aktuellen Wert fixieren, dann auf fast 0 abbremsen
rate.cancelScheduledValues(now);
rate.setValueAtTime(rate.value, now);
rate.exponentialRampToValueAtTime(0.01, now + duration);
// danach die Quelle stoppen
source.stop(now + duration);
};
// Aufruf, z. B. beim Pausieren eines Spiels:
// tapeStop(musicSource, ctx);
Pitch-Regler mit sanftem Übergang
const ctx = new AudioContext();
let source; // läuft bereits, z. B. mit loop = true
const slider = document.querySelector('#rate'); // <input type="range" min="0.5" max="2" step="0.01">
slider.addEventListener('input', (event) => {
if (!source) return;
const target = Number(event.target.value);
// setTargetAtTime verhindert hörbare Sprünge
source.playbackRate.setTargetAtTime(target, ctx.currentTime, 0.05);
});
// Wichtig · Fallstricke
- Tonhöhe ändert sich mit:
playbackRateverschiebt Tempo und Tonhöhe immer gemeinsam. Wenn du das Tempo ohne Tonhöhenänderung anpassen willst, brauchst du einHTMLMediaElementmitpreservesPitchoder einen eigenen Time-Stretching-Algorithmus, etwa in einemAudioWorklet. - Nicht zuweisbar:
source.playbackRate = 2hat keine Wirkung, weil die Eigenschaft schreibgeschützt ist, und löst im Strict Mode einenTypeErroraus. Setze stattdessensource.playbackRate.value = 2. - k-rate fest vorgegeben: Wenn du
automationRateauf"a-rate"setzt, wird einInvalidStateErrorausgelöst. Sehr schnelle Modulationen werden deshalb nur blockweise (alle 128 Samples) übernommen. - Die Dauer ändert sich:
start(when, offset, duration)undloopStart/loopEndbeziehen sich auf die Pufferzeit, nicht auf die Echtzeit. BeiplaybackRate = 2ist ein Puffer von 4 Sekunden also nach 2 Sekunden fertig. Dasended-Event richtet sich nach der tatsächlichen Wiedergabe. - Negative Werte / Rückwärtswiedergabe: Die Spezifikation erlaubt negative Raten, die Browser setzen das aber unterschiedlich um. Wenn du zuverlässig rückwärts abspielen willst, kopiere den Puffer und kehre die Kanaldaten mit
getChannelData().reverse()um. exponentialRampToValueAtTime()akzeptiert weder0als Zielwert noch einen Vorzeichenwechsel. Nimm für „Stopp“-Effekte einen kleinen positiven Wert wie0.01.- Ein
AudioContextstartet meist erst nach einer Nutzerinteraktion (Autoplay-Richtlinien). Rufe dazuctx.resume()in einem Klick-Handler auf.