Start · Sprachen · JavaScript · Referenz · AudioBuffer.copyFromChannel()

AudioBuffer.copyFromChannel()

Methode

Kopiert die Sample-Daten eines Kanals eines <code>AudioBuffer</code> ab einer optionalen Startposition in ein vorhandenes <code>Float32Array</code>.

seit JavaScript Baseline: alle modernen Browser (Safari ab 14.1) Kategorie: webapi

Signatur

AudioBuffer.prototype.copyFromChannel(destination, channelNumber, bufferOffset)

Beschreibung

copyFromChannel() liest die PCM-Samples eines bestimmten Kanals aus einem AudioBuffer und schreibt sie in ein Float32Array, das du selbst anlegst. Die Werte liegen normalerweise im Bereich −1.0 bis +1.0. Kopiert wird ab dem Index bufferOffset im Quellkanal, und zwar so viele Samples, wie in das Ziel-Array passen oder im Kanal noch übrig sind (je nachdem, was kleiner ist).

Im Unterschied zu getChannelData(), das eine direkte Referenz auf die internen Kanaldaten zurückgibt, entsteht hier eine unabhängige Kopie. Wenn du das Ziel-Array später änderst, bleibt der Buffer unverändert. Außerdem kannst du ein vorhandenes Array immer wieder befüllen, also etwa blockweise durch einen langen Buffer gehen, ohne jedes Mal neuen Speicher anzulegen.

Typische Einsatzfälle sind Wellenform-Darstellungen, Pegel- und Spitzenwertanalyse, das Ausschneiden von Abschnitten, das Kopieren zwischen Buffern (zusammen mit copyToChannel()) und die Übergabe von Audiodaten an Worker oder Encoder.

Parameter

Name Typ Default Beschreibung
$destination Pflicht Float32Array Ziel-Array, in das die Samples geschrieben werden. Seine Länge bestimmt, wie viele Samples höchstens kopiert werden.
$channelNumber Pflicht number Index des Quellkanals, bei 0 beginnend (bei Stereo: 0 = links, 1 = rechts). Muss kleiner als numberOfChannels sein.
$bufferOffset number 0 Sample-Index im Quellkanal, ab dem kopiert wird. Nützlich, um Abschnitte oder Blöcke auszulesen.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Das Ergebnis steht im übergebenen destination-Array.

Beispiele

Einen Kanal vollständig kopieren

const ctx = new AudioContext();
const buffer = new AudioBuffer({ numberOfChannels: 2, length: 4, sampleRate: ctx.sampleRate });

// Linken Kanal mit Testdaten füllen
buffer.copyToChannel(new Float32Array([0.1, 0.5, -0.5, 1]), 0);

const links = new Float32Array(buffer.length);
buffer.copyFromChannel(links, 0);

links[0] = 0.9; // ändert NICHT den Buffer
console.log(Array.from(links));
console.log(buffer.getChannelData(0)[0]);
[0.8999999761581421, 0.5, -0.5, 1] 0.10000000149011612

Einen Ausschnitt ab einer Zeitposition auslesen

const sekundeAusschneiden = (buffer, startSekunden, kanal = 0) => {
  const start = Math.floor(startSekunden * buffer.sampleRate);
  const ziel = new Float32Array(buffer.sampleRate); // 1 Sekunde
  buffer.copyFromChannel(ziel, kanal, start);
  return ziel;
};

const response = await fetch('/audio/song.mp3');
const ctx = new AudioContext();
const buffer = await ctx.decodeAudioData(await response.arrayBuffer());

const ausschnitt = sekundeAusschneiden(buffer, 10);
console.log(ausschnitt.length === buffer.sampleRate);
true

Spitzenwerte für eine Wellenform-Anzeige blockweise berechnen

const berechnePeaks = (buffer, anzahlBalken, kanal = 0) => {
  const blockGroesse = Math.floor(buffer.length / anzahlBalken);
  const block = new Float32Array(blockGroesse); // wird wiederverwendet
  const peaks = [];

  for (let i = 0; i < anzahlBalken; i++) {
    buffer.copyFromChannel(block, kanal, i * blockGroesse);
    let max = 0;
    for (const s of block) max = Math.max(max, Math.abs(s));
    peaks.push(Number(max.toFixed(3)));
  }
  return peaks;
};

const ctx = new OfflineAudioContext(1, 44100, 44100);
const buffer = ctx.createBuffer(1, 44100, 44100);
const daten = buffer.getChannelData(0);
for (let i = 0; i < daten.length; i++) daten[i] = Math.sin(i / 20) * (i / daten.length);

console.log(berechnePeaks(buffer, 4));
[0.25, 0.5, 0.75, 1]

Kanal zwischen zwei Buffern kopieren (Mono zu Stereo)

const monoZuStereo = (ctx, mono) => {
  const stereo = ctx.createBuffer(2, mono.length, mono.sampleRate);
  const tmp = new Float32Array(mono.length);
  mono.copyFromChannel(tmp, 0);
  stereo.copyToChannel(tmp, 0);
  stereo.copyToChannel(tmp, 1);
  return stereo;
};

const ctx = new AudioContext();
const mono = ctx.createBuffer(1, 1000, ctx.sampleRate);
const stereo = monoZuStereo(ctx, mono);
console.log(stereo.numberOfChannels);
2

// Wichtig · Fallstricke

  • Ungültiger Kanal: Ist channelNumber größer oder gleich numberOfChannels, wird eine IndexSizeError-DOMException geworfen. Prüfe daher vorher buffer.numberOfChannels.
  • Falscher Zieltyp: destination muss ein Float32Array sein. Normale Arrays oder Float64Array führen zu einem TypeError.
  • Keine Fehlermeldung bei zu kurzem Rest: Wenn ab bufferOffset weniger Samples übrig sind, als das Ziel aufnehmen kann, werden nur die vorhandenen kopiert. Der Rest des Ziel-Arrays bleibt, wie er war, also nicht automatisch 0. Beim Wiederverwenden eines Arrays solltest du es vorher mit fill(0) leeren. Ältere Browser warfen bei einem Offset außerhalb des Buffers teils eine IndexSizeError.
  • Kopie oder Referenz: getChannelData() gibt die internen Daten ohne Kopie zurück und ist für reine Lesezugriffe oft schneller. copyFromChannel() nimmst du, wenn du die Daten unabhängig vom Buffer brauchst.
  • Kompatibilität: In Chrome, Firefox und Edge seit Langem verfügbar, in Safari erst ab Version 14.1. Für sehr alte Safari-Versionen kannst du auf getChannelData(n).slice() ausweichen.