Naar inhoud
Inloggen

/docs · MixLab · Deep

Mid/Side-decompositie in WebAudio

Som- en verschilsignalen zijn de juiste manier om over stereo na te denken. Hier is de WebAudio API-code om het te doen.


De stereokanalen die je uit een doorsnee browser-audiobestand binnenkrijgt, zijn links en rechts. De stereokanalen die je oren daadwerkelijk ontleden, zijn midden en zijkanten. Mid/Side-decompositie vertaalt tussen beide, en zodra je dat hebt, worden veel “stereo”-vraagstukken triviaal.

De wiskunde

Voor elke sample:

mid  = (L + R) / 2
side = (L - R) / 2

En terug:

L = mid + side
R = mid - side

Dat is alles. Twee optellingen en een paar delingen per sample. Er zit geen verborgen slimmigheid in.

In WebAudio

WebAudio heeft een ChannelSplitterNode en een ChannelMergerNode. Met een paar gain-trappen bouw je M/S binnen de graph:

const source = ctx.createMediaElementSource(audioEl);
const splitter = ctx.createChannelSplitter(2);
const merger = ctx.createChannelMerger(2);

// L → mid+side, R → mid−side
const lGain = ctx.createGain(); lGain.gain.value = 0.5;
const rGainPos = ctx.createGain(); rGainPos.gain.value = 0.5;
const rGainNeg = ctx.createGain(); rGainNeg.gain.value = -0.5;

source.connect(splitter);

// Mid = 0.5*L + 0.5*R → channel 0 of merger
splitter.connect(lGain, 0);
splitter.connect(rGainPos, 1);
lGain.connect(merger, 0, 0);
rGainPos.connect(merger, 0, 0);

// Side = 0.5*L + (-0.5)*R → channel 1 of merger
splitter.connect(lGain, 0);
splitter.connect(rGainNeg, 1);
lGain.connect(merger, 0, 1);
rGainNeg.connect(merger, 0, 1);

merger.connect(ctx.destination);

Voor offline-analyse op een gedecodeerde AudioBuffer is het goedkoper om het rechtstreeks op de typed arrays te doen:

const left = buffer.getChannelData(0);
const right = buffer.getChannelData(1) ?? left;
const mid = new Float32Array(left.length);
const side = new Float32Array(left.length);
for (let i = 0; i < left.length; i++) {
  mid[i]  = (left[i] + right[i]) * 0.5;
  side[i] = (left[i] - right[i]) * 0.5;
}

Dit is wat MixLab Analyzer onder de motorkap doet.

Wat je kunt meten zodra je M/S hebt

  • Echte stereobreedte. De verhouding tussen de energie van de zijkanten en die van het midden is een directe maat voor hoeveel “stereo” er in de mix zit. Een RMS-gebaseerde vergelijking is robuust en snel:

    const widthRatio = rms(side) / (rms(mid) + 1e-6);
  • Mono-compatibiliteit. Als rms(side) groot is maar de Pearson-correlatie tussen L en R sterk negatief, dan verliest de mix content bij het sommeren naar mono. Het melden waard.

  • Faseproblemen. Een negatieve correlatie met hoge zijkant-energie is het klassieke symptoom van een ergens stroomopwaarts omgedraaid kanaal.

  • Stereo-dynamiekbewerking. Mid en side onafhankelijk behandelen (comprimeer het midden, laat de zijkanten met rust) is de basis van mid/side-mastering. Je kunt de hele effectketen volledig in WebAudio-nodes prototypen.

Veelgemaakte fouten

  1. De factor 0.5 vergeten. Zonder die factor bereken je L+R en L−R, niet mid en side. De energieschaling zit er dan 6 dB naast.
  2. Aannemen dat monobestanden geen zijkanten hebben. Een monobestand dat als stereo wordt ingelezen (L = R) heeft precies nul zijkant-energie. Dat is een bruikbaar detectiesignaal.
  3. In dB werken vóór het recombineren. Niet doen. Blijf lineair tot helemaal op het einde.

Wanneer M/S het verkeerde gereedschap is

Mid/Side is een som-en-verschil-kader voor de kanalen die je hebt. Het zegt niets over de ruimtelijke perceptie van die kanalen; daarvoor heb je binaurale / HRTF-bewuste analyse nodig. Bouw je iets dat moet kunnen redeneren over waar een geluid zich in het klankbeeld bevindt, dan is M/S het verkeerde uitgangspunt.

Voor mixanalyse en zo goed als elke masteringbeslissing is M/S juist het juiste kader. Het is ook het kader dat de meeste thuisproducers het meest verrast wanneer ze het voor het eerst zien.