Start · Sprachen · JavaScript · Referenz · ScriptProcessorNode

ScriptProcessorNode

Schnittstelle

Veralteter Audio-Knoten der Web Audio API, der Audiodaten blockweise per <code>audioprocess</code>-Event an JavaScript übergibt, um sie zu erzeugen, zu verändern oder zu analysieren.

seit JavaScript Veraltet (deprecated) – weiterhin in allen gängige deprecated seit ja Kategorie: webapi

Signatur

interface ScriptProcessorNode extends AudioNode

Beschreibung

ScriptProcessorNode ist ein AudioNode der Web Audio API, über den Audiodaten direkt mit JavaScript verarbeitet werden. Der Knoten hat einen Eingangs- und einen Ausgangspuffer. Sobald ein Block von bufferSize Samples bereitliegt, wird ein AudioProcessingEvent (audioprocess) ausgelöst. Im Handler liest man aus event.inputBuffer und schreibt in event.outputBuffer.

Man erzeugt ihn nicht per Konstruktor, sondern mit der Fabrikmethode BaseAudioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels). Die unten beschriebenen Parameter gehören zu dieser Methode. Der wichtigste Wert auf dem Knoten selbst ist die schreibgeschützte Eigenschaft bufferSize. Außerdem gibt es den Event-Handler onaudioprocess.

Typische Einsatzgebiete sind eigene Effekte (etwa Verstärkung, Verzerrung oder Bitcrusher), Pegelmessung, das Aufnehmen roher PCM-Daten oder synthetisch erzeugte Signale wie Rauschen. Die Verarbeitung läuft allerdings im Haupt-Thread. Wenn die Oberfläche stark ausgelastet ist, kommt es deshalb zu Aussetzern und zusätzlicher Latenz.

Der Knoten ist in der Spezifikation als veraltet markiert und wird durch AudioWorkletNode ersetzt, der in einem eigenen Audio-Thread läuft. Für neuen Code sollte man AudioWorklet verwenden. ScriptProcessorNode ist vor allem für sehr alte Browser oder bestehenden Code gedacht.

Parameter

Name Typ Default Beschreibung
$bufferSize number 0 Parameter von createScriptProcessor(): Anzahl der Sample-Frames pro audioprocess-Aufruf. Erlaubt sind 256, 512, 1024, 2048, 4096, 8192 und 16384. Bei 0 wählt der Browser einen passenden Wert. Kleine Werte ergeben weniger Latenz, aber ein höheres Risiko für Aussetzer.
$numberOfInputChannels number 2 Anzahl der Eingangskanäle (maximal 32). numberOfInputChannels und numberOfOutputChannels dürfen nicht beide 0 sein.
$numberOfOutputChannels number 2 Anzahl der Ausgangskanäle (maximal 32).

Rückgabewert

Typ
ScriptProcessorNode
Beschreibung
createScriptProcessor() gibt einen neuen ScriptProcessorNode zurück. Er hat die schreibgeschützte Eigenschaft bufferSize (number) und den Handler onaudioprocess.

Beispiele

Knoten erzeugen und Lautstärke halbieren

const ctx = new AudioContext();
const osc = ctx.createOscillator();
const processor = ctx.createScriptProcessor(4096, 1, 1);

processor.onaudioprocess = (event) => {
  const input = event.inputBuffer.getChannelData(0);
  const output = event.outputBuffer.getChannelData(0);
  for (let i = 0; i < input.length; i++) {
    output[i] = input[i] * 0.5; // Verstärkung 0.5
  }
};

osc.connect(processor);
processor.connect(ctx.destination);
osc.start();
console.log(processor.bufferSize);
4096

Weißes Rauschen erzeugen (nur Ausgang)

const ctx = new AudioContext();
// Keine Eingänge, zwei Ausgangskanäle
const noise = ctx.createScriptProcessor(2048, 0, 2);

noise.addEventListener('audioprocess', ({ outputBuffer }) => {
  for (let ch = 0; ch < outputBuffer.numberOfChannels; ch++) {
    const data = outputBuffer.getChannelData(ch);
    for (let i = 0; i < data.length; i++) {
      data[i] = Math.random() * 2 - 1;
    }
  }
});

noise.connect(ctx.destination);
// Stoppen: noise.disconnect();

Mikrofonpegel (RMS) messen

const startMeter = async () => {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const ctx = new AudioContext();
  const source = ctx.createMediaStreamSource(stream);
  const meter = ctx.createScriptProcessor(1024, 1, 1);

  meter.onaudioprocess = (e) => {
    const samples = e.inputBuffer.getChannelData(0);
    let sum = 0;
    for (const s of samples) sum += s * s;
    const rms = Math.sqrt(sum / samples.length);
    console.log(`Pegel: ${(20 * Math.log10(rms || 1e-8)).toFixed(1)} dBFS`);
  };

  source.connect(meter);
  // Viele Browser feuern das Event nur, wenn der Knoten mit dem Ziel verbunden ist
  meter.connect(ctx.destination);
};

startMeter();
Pegel: -42.3 dBFS (Werte variieren)

// Wichtig · Fallstricke

  • Veraltet: Für neue Projekte AudioWorkletNode verwenden. Eine Entfernung ist derzeit nicht angekündigt, aber auch nicht auszuschließen.
  • Haupt-Thread: Aufwendige Berechnungen, DOM-Arbeit oder die Garbage Collection können zu Knacksern und Aussetzern führen. Im Handler möglichst keine Objekte anlegen.
  • Das audioprocess-Event wird in manchen Browsern (z. B. Chrome) nur ausgelöst, wenn der Knoten mit einem Ausgang verbunden ist, etwa mit ctx.destination. Das gilt auch dann, wenn er nur Daten analysiert.
  • Der Ausgangspuffer muss vollständig beschrieben werden. Andernfalls sind die Samples zwar meist Stille, in manchen Browsern aber undefiniert.
  • Ein ungültiger bufferSize löst einen IndexSizeError aus. Sind beide Kanalzahlen 0, gibt es einen NotSupportedError.
  • Durch die Pufferung entsteht immer eine zusätzliche Latenz von mindestens einem Block (bei 4096 Samples und 48 kHz etwa 85 ms).
  • Einen new ScriptProcessorNode()-Konstruktor gibt es nicht. Der Knoten wird nur über createScriptProcessor() erzeugt.
  • Mikrofonzugriff per getUserMedia funktioniert nur in einem sicheren Kontext (HTTPS). Außerdem muss der AudioContext wegen der Autoplay-Regeln oft erst nach einer Nutzeraktion gestartet werden (ctx.resume()).