Start · Sprachen · JavaScript · Referenz · AudioBufferSourceNode.playbackRate

AudioBufferSourceNode.playbackRate

Eigenschaft

Schreibgeschützter k-rate-<code>AudioParam</code>, der die Wiedergabegeschwindigkeit eines <code>AudioBufferSourceNode</code> bestimmt (Standard: <code>1</code>).

seit JavaScript Baseline: alle modernen Browser (Web Audio API) Kategorie: webapi

Signatur

AudioBufferSourceNode.playbackRate

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

Typ
AudioParam
Beschreibung
Ein 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');
});
1 0.5

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)));
};
["1.000", "1.260", "1.498"]

„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: playbackRate verschiebt Tempo und Tonhöhe immer gemeinsam. Wenn du das Tempo ohne Tonhöhenänderung anpassen willst, brauchst du ein HTMLMediaElement mit preservesPitch oder einen eigenen Time-Stretching-Algorithmus, etwa in einem AudioWorklet.
  • Nicht zuweisbar: source.playbackRate = 2 hat keine Wirkung, weil die Eigenschaft schreibgeschützt ist, und löst im Strict Mode einen TypeError aus. Setze stattdessen source.playbackRate.value = 2.
  • k-rate fest vorgegeben: Wenn du automationRate auf "a-rate" setzt, wird ein InvalidStateError ausgelöst. Sehr schnelle Modulationen werden deshalb nur blockweise (alle 128 Samples) übernommen.
  • Die Dauer ändert sich: start(when, offset, duration) und loopStart/loopEnd beziehen sich auf die Pufferzeit, nicht auf die Echtzeit. Bei playbackRate = 2 ist ein Puffer von 4 Sekunden also nach 2 Sekunden fertig. Das ended-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 weder 0 als Zielwert noch einen Vorzeichenwechsel. Nimm für „Stopp“-Effekte einen kleinen positiven Wert wie 0.01.
  • Ein AudioContext startet meist erst nach einer Nutzerinteraktion (Autoplay-Richtlinien). Rufe dazu ctx.resume() in einem Klick-Handler auf.