{"id":19924,"date":"2026-09-17T20:06:47","date_gmt":"2026-09-17T18:06:47","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/stereo-correlation-mid-side-meter\/"},"modified":"2026-09-17T20:06:47","modified_gmt":"2026-09-17T18:06:47","slug":"stereo-correlation-mid-side-meter","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/","title":{"rendered":"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file"},"content":{"rendered":"<div class=\"lw-sk\" id=\"sk-wurzel\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<style>\n.lw-sk .sk-zone { border: 2px dashed var(--border, #2a2a35); border-radius: 8px; padding: 24px 16px; text-align: center; transition: border-color 0.15s, background 0.15s; }\n.lw-sk .sk-zone.sk-ueber { border-color: var(--accent, #2ba6df); background: var(--bg-body, #14141a); }\n.lw-sk .sk-kacheln { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 14px 0 4px; }\n.lw-sk .sk-kachel { background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 11px 14px; min-width: 0; }\n.lw-sk .sk-kachel-name { font-size: 0.74rem; color: var(--text-secondary, #a0a0b0); text-transform: uppercase; letter-spacing: 0.4px; }\n.lw-sk .sk-kachel-wert { font-family: monospace; font-size: 1.4rem; font-weight: 700; color: var(--text-primary, #e8e8ee); line-height: 1.25; white-space: nowrap; }\n.lw-sk .sk-einheit { font-size: 0.8rem; font-weight: 400; color: var(--text-secondary, #a0a0b0); margin-left: 4px; }\n.lw-sk .sk-tabelle { overflow-x: auto; }\n.lw-sk table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }\n.lw-sk th, .lw-sk td { text-align: right; padding: 6px 10px; border-bottom: 1px solid var(--border, #2a2a35); white-space: nowrap; }\n.lw-sk th:first-child, .lw-sk td:first-child { text-align: left; }\n.lw-sk th { color: var(--text-primary, #e8e8ee); }\n.lw-sk td { color: var(--text-primary, #e8e8ee); font-family: monospace; }\n.lw-sk td.sk-name { font-family: inherit; color: var(--text-secondary, #a0a0b0); }\n.lw-sk .sk-ok { color: var(--ok, #7ee787) !important; }\n.lw-sk .sk-warn { color: var(--sk-warn); }\n.lw-sk .sk-fail { color: var(--fail, #ff7b72) !important; }\n.lw-sk { --sk-warn: #e8a33d; }\n:root[data-theme=\"light\"] .lw-sk { --sk-warn: #8f5300; }\n.lw-sk .sk-befund { background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left-width: 3px; border-radius: 8px; padding: 11px 14px; margin: 0 0 8px; }\n.lw-sk .sk-befund.sk-b-ok { border-left-color: var(--ok, #7ee787); }\n.lw-sk .sk-befund.sk-b-warn { border-left-color: var(--sk-warn); }\n.lw-sk .sk-befund.sk-b-fail { border-left-color: var(--fail, #ff7b72); }\n.lw-sk .sk-befund b { color: var(--text-primary, #e8e8ee); }\n.lw-sk .sk-balken { height: 8px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 4px; overflow: hidden; }\n.lw-sk .sk-balken > div { height: 100%; width: 0; background: var(--accent, #2ba6df); }\n.lw-sk .sk-h { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 24px 0 8px; }\n.lw-sk .sk-klein { font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); line-height: 1.55; }\n.lw-sk canvas { display: block; width: 100%; max-width: 100%; }\n.lw-sk a { color: var(--accent, #2ba6df); }\n@media (max-width: 480px) {\n    .lw-sk .sk-kacheln { grid-template-columns: 1fr 1fr; gap: 8px; }\n    .lw-sk .sk-kachel { padding: 10px 11px; }\n    .lw-sk .sk-kachel-wert { font-size: 1.15rem; }\n    .lw-sk th, .lw-sk td { padding: 6px 6px; }\n}\n<\/style>\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 18px;\">A mix can sound wide on headphones and collapse in mono. The meter reads an audio file in the browser and measures the correlation between the left and right channel, the share of the side signal, the level a mono sum loses and the balance of the channels, in total and in three frequency bands, plus the correlation over time.<\/p>\n<div id=\"sk-zone\" class=\"sk-zone\">\n<p style=\"margin: 0 0 12px; color: var(--text-primary, #e8e8ee); font-weight: 700;\">Drop an audio file here<\/p>\n<p>        <button id=\"sk-knopf\" type=\"button\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 11px 22px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Choose file<\/button><br \/>\n        <input id=\"sk-datei\" type=\"file\" accept=\"audio\/*,.wav,.wave,.aif,.aiff,.flac,.mp3,.m4a,.mp4,.aac,.ogg,.oga,.opus\" hidden><\/p>\n<p class=\"sk-klein\" style=\"margin: 12px 0 0;\">The file stays in the browser; nothing is uploaded. WAV, FLAC, MP3, M4A, OGG and Opus, as far as the browser plays them.<\/p>\n<\/p><\/div>\n<div id=\"sk-status\" style=\"margin-top: 16px;\" hidden>\n<div id=\"sk-status-text\" data-mp-mask class=\"sk-klein\" style=\"margin-bottom: 6px;\"><\/div>\n<div class=\"sk-balken\">\n<div id=\"sk-fortschritt\"><\/div>\n<\/div><\/div>\n<div id=\"sk-ausgabe\" data-mp-mask style=\"margin-top: 18px;\" aria-live=\"polite\"><\/div>\n<div class=\"sk-h\">What the numbers mean<\/div>\n<p class=\"sk-klein\" style=\"margin: 0 0 6px;\">The correlation compares the left and right channel: +1 means the same signal (unchanged in mono), 0 means independent, \u22121 means opposite phase, where the mono sum cancels out. In the vectorscope of FL Studio a centred mono signal appears as a vertical line, while a horizontal line means the channels are 180 degrees out of phase.<\/p>\n<p class=\"sk-klein\" style=\"margin: 0 0 6px;\">Mid is (L + R) \u00f7 2, side is (L \u2212 R) \u00f7 2. The value given is the distance between both RMS levels: \u22126 dB is narrow, 0 dB means side and mid are equally loud. According to the FL Studio manual, stereo tools work on exactly this difference between the channels.<\/p>\n<p class=\"sk-klein\" style=\"margin: 0 0 6px;\">The mono sum is the level of (L + R) \u00f7 2 against the RMS level of the stereo signal. 0 dB means nothing is lost; independent channels lose around 3 dB, out-of-phase content more.<\/p>\n<p class=\"sk-klein\" style=\"margin: 0 0 6px;\">The bands come from second-order high-pass and low-pass filters, identical for both channels. This shows whether only the highs are wide or the bass drifts apart as well.<\/p>\n<p class=\"sk-klein\" style=\"margin: 20px 0 0;\">Sources:<br \/>\n        <a href=\"https:\/\/www.image-line.com\/fl-studio-learning\/fl-studio-online-manual\/html\/plugins\/Wave%20Candy.htm\" rel=\"noopener\">Wave Candy<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/www.image-line.com\/fl-studio-learning\/fl-studio-online-manual\/html\/plugins\/Fruity%20Stereo%20Enhancer.htm\" rel=\"noopener\">Fruity Stereo Enhancer<\/a>\n    <\/p>\n<p class=\"sk-klein\" style=\"font-size: 0.8rem; margin: 14px 0 0;\">Everything is calculated in the browser; the file never leaves the computer. The whole file is measured, so short out-of-phase passages hardly show in the total and appear in the curve instead. Channels beyond the first two are ignored.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"A mix can sound wide on headphones and collapse in mono. The meter reads an audio file in the browser and measures the correlation between the left and right channel, the share of the side signal, the level a mono sum loses and the balance of the channels, in total and in three frequency bands, plus the correlation over time.\",\"zone_titel\":\"Drop an audio file here\",\"knopf_datei\":\"Choose file\",\"zone_hinweis\":\"The file stays in the browser; nothing is uploaded. WAV, FLAC, MP3, M4A, OGG and Opus, as far as the browser plays them.\",\"status_lesen\":\"Reading the file \u2026\",\"status_dekodieren\":\"Decoding \u2026\",\"status_messen\":\"Measuring \u2026\",\"fehler_dekodieren\":\"The file could not be decoded. The browser has to be able to play the format.\",\"fehler_webaudio\":\"This browser offers no Web Audio decoding.\",\"fehler_speicher\":\"The file is too large for the browser\\u0027s memory.\",\"fehler_leer\":\"The file contains no samples.\",\"fehler_format\":\"This format cannot be read here: {detail}.\",\"datei_satz\":\"{name} \u00b7 {dauer} \u00b7 {rate} kHz \u00b7 {kanaele}\",\"kanal_mono\":\"1 channel\",\"kanal_stereo\":\"2 channels\",\"kanal_mehr\":\"{n} channels (the first two are measured)\",\"k_korrelation\":\"Correlation\",\"k_seite\":\"Side against mid\",\"k_mono\":\"Mono sum\",\"k_balance\":\"Balance L against R\",\"h_befunde\":\"Findings\",\"h_baender\":\"Bands\",\"sp_band\":\"Band\",\"sp_korrelation\":\"Correlation\",\"sp_seite\":\"Side against mid (dB)\",\"sp_mono\":\"Mono sum (dB)\",\"sp_anteil\":\"Share of the energy (%)\",\"band_tief\":\"Lows ({von}\u2013{bis} Hz)\",\"band_mitten\":\"Mids ({von}\u2013{bis} Hz)\",\"band_hoehen\":\"Highs ({von}\u2013{bis} Hz)\",\"h_verlauf\":\"Correlation over time\",\"verlauf_hinweis\":\"One bar per {fenster} s. {unter} % of the windows lie below zero, the lowest value is {kleinste}.\",\"h_erklaerung\":\"What the numbers mean\",\"erkl_korrelation\":\"The correlation compares the left and right channel: +1 means the same signal (unchanged in mono), 0 means independent, \u22121 means opposite phase, where the mono sum cancels out. In the vectorscope of FL Studio a centred mono signal appears as a vertical line, while a horizontal line means the channels are 180 degrees out of phase.\",\"erkl_seite\":\"Mid is (L + R) \u00f7 2, side is (L \u2212 R) \u00f7 2. The value given is the distance between both RMS levels: \u22126 dB is narrow, 0 dB means side and mid are equally loud. According to the FL Studio manual, stereo tools work on exactly this difference between the channels.\",\"erkl_mono\":\"The mono sum is the level of (L + R) \u00f7 2 against the RMS level of the stereo signal. 0 dB means nothing is lost; independent channels lose around 3 dB, out-of-phase content more.\",\"erkl_baender\":\"The bands come from second-order high-pass and low-pass filters, identical for both channels. This shows whether only the highs are wide or the bass drifts apart as well.\",\"quellen_titel\":\"Sources\",\"grenze\":\"Everything is calculated in the browser; the file never leaves the computer. The whole file is measured, so short out-of-phase passages hardly show in the total and appear in the curve instead. Channels beyond the first two are ignored.\",\"befund_mono\":\"The file is mono || Both channels are identical; correlation, side share and mono sum say nothing here.\",\"befund_gegenphase\":\"The channels work against each other || The correlation is {k}. In mono the file loses {mono} dB; large parts cancel out.\",\"befund_mono_verlust\":\"The mono sum loses {mono} dB || At a correlation of {k}, audible level disappears in mono. This affects club systems, phones and many speakers in shops.\",\"befund_bass_breit\":\"The bass is not centred || Up to {hz} Hz the correlation is {k}. Low content in the side loses the most level in mono.\",\"befund_sehr_breit\":\"Side louder than mid || The side signal lies {seite} dB above the mid. That sounds wide on headphones, but little remains in mono.\",\"befund_balance_links\":\"The left channel is louder || The left channel lies {db} dB above the right one.\",\"befund_balance_rechts\":\"The right channel is louder || The right channel lies {db} dB above the left one.\",\"befund_kurz\":\"Short excerpt || The file lasts {s} s. That is little for a reliable overall value.\",\"befund_gut\":\"Nothing conspicuous || Correlation {k}, side {seite} dB against the mid. The mono sum stays almost complete.\",\"dezimal\":\".\"};<\/p>\n<p>    \/\/ KERN-ANFANG ------------------------------------------------------------\n    \/\/ Korrelation, Mitte\/Seite und Mono-Summe, gesamt und in drei Baendern.\n    \/\/ Rein rechnend, ohne Dokument: derselbe Text laeuft im Browser und im Test.<\/p>\n<p>    var FENSTER_S = 0.4;        \/\/ Fensterlaenge des Verlaufs\n    var STUECK = 1 << 18;       \/\/ Abtastwerte je Rechenschritt\n    var BAENDER = [\n        { id: 'tief', von: 20, bis: 120 },\n        { id: 'mitten', von: 120, bis: 2000 },\n        { id: 'hoehen', von: 2000, bis: 20000 }\n    ];\n\n    function db(x) { return x > 0 ? 20 * Math.log(x) \/ Math.LN10 : -Infinity; }<\/p>\n<p>    \/\/ Biquad nach der Kochbuch-Formel (Butterworth, Q = 1\/sqrt(2)).\n    function biquad(art, f0, fs) {\n        var grenze = Math.min(Math.max(f0, 1), fs * 0.45);\n        var w0 = 2 * Math.PI * grenze \/ fs, c = Math.cos(w0), s = Math.sin(w0);\n        var alpha = s \/ (2 * Math.SQRT1_2);\n        var a0 = 1 + alpha, a1 = -2 * c, a2 = 1 - alpha, b0, b1, b2;\n        if (art === 'hp') {\n            b0 = (1 + c) \/ 2; b1 = -(1 + c); b2 = (1 + c) \/ 2;\n        } else {\n            b0 = (1 - c) \/ 2; b1 = 1 - c; b2 = (1 - c) \/ 2;\n        }\n        return { b0: b0 \/ a0, b1: b1 \/ a0, b2: b2 \/ a0, a1: a1 \/ a0, a2: a2 \/ a0 };\n    }\n    function zustand() { return { x1: 0, x2: 0, y1: 0, y2: 0 }; }\n    function schritt(k, z, x) {\n        var y = k.b0 * x + k.b1 * z.x1 + k.b2 * z.x2 - k.a1 * z.y1 - k.a2 * z.y2;\n        z.x2 = z.x1; z.x1 = x; z.y2 = z.y1; z.y1 = y;\n        return y;\n    }\n    \/\/ Ein Band: Hochpass und Tiefpass hintereinander, je zweiter Ordnung.\n    function bandFiltern(daten, fs, von, bis) {\n        var hp = biquad('hp', von, fs), lp = biquad('lp', bis, fs);\n        var zh = zustand(), zl = zustand(), aus = new Float32Array(daten.length);\n        for (var i = 0; i < daten.length; i++) { aus[i] = schritt(lp, zl, schritt(hp, zh, daten[i])); }\n        return aus;\n    }\n\n    function summenAnlegen() { return { ll: 0, rr: 0, lr: 0, mm: 0, ss: 0, n: 0 }; }\n    function summenNehmen(s, l, r) {\n        s.ll += l * l; s.rr += r * r; s.lr += l * r;\n        var m = (l + r) \/ 2, seite = (l - r) \/ 2;\n        s.mm += m * m; s.ss += seite * seite; s.n++;\n    }\n    function auswerten(s) {\n        var nenner = Math.sqrt(s.ll * s.rr);\n        var rmsL = Math.sqrt(s.ll \/ (s.n || 1)), rmsR = Math.sqrt(s.rr \/ (s.n || 1));\n        var rmsM = Math.sqrt(s.mm \/ (s.n || 1)), rmsS = Math.sqrt(s.ss \/ (s.n || 1));\n        var rmsStereo = Math.sqrt((s.ll + s.rr) \/ (2 * (s.n || 1)));\n        return {\n            korrelation: nenner > 0 ? s.lr \/ nenner : 0,\n            seite_db: db(rmsS) - db(rmsM),\n            mono_db: db(rmsM) - db(rmsStereo),\n            balance_db: db(rmsL) - db(rmsR),\n            rms_l_db: db(rmsL), rms_r_db: db(rmsR), rms_m_db: db(rmsM), rms_s_db: db(rmsS),\n            energie: s.ll + s.rr\n        };\n    }<\/p>\n<p>    \/\/ Messung in Stuecken, damit lange Dateien die Oberflaeche nicht anhalten.\n    function messungAnlegen(kanaele, fs) {\n        var l = kanaele[0], r = kanaele.length > 1 ? kanaele[1] : kanaele[0];\n        var n = Math.min(l.length, r.length);\n        var filter = BAENDER.map(function (b) {\n            return {\n                hpL: biquad('hp', b.von, fs), lpL: biquad('lp', b.bis, fs),\n                hpR: biquad('hp', b.von, fs), lpR: biquad('lp', b.bis, fs),\n                zhl: zustand(), zll: zustand(), zhr: zustand(), zlr: zustand(),\n                summen: summenAnlegen()\n            };\n        });\n        return {\n            l: l, r: r, n: n, fs: fs, pos: 0, kanaeleAnzahl: kanaele.length,\n            gesamt: summenAnlegen(), filter: filter, spitzeL: 0, spitzeR: 0,\n            fensterLaenge: Math.max(1, Math.round(FENSTER_S * fs)), fenster: summenAnlegen(), verlauf: []\n        };\n    }\n    function messungSchritt(m, wieviel) {\n        var ende = Math.min(m.n, m.pos + wieviel);\n        for (var i = m.pos; i < ende; i++) {\n            var l = m.l[i], r = m.r[i];\n            summenNehmen(m.gesamt, l, r);\n            summenNehmen(m.fenster, l, r);\n            if (Math.abs(l) > m.spitzeL) { m.spitzeL = Math.abs(l); }\n            if (Math.abs(r) > m.spitzeR) { m.spitzeR = Math.abs(r); }\n            for (var b = 0; b < m.filter.length; b++) {\n                var f = m.filter[b];\n                summenNehmen(f.summen, schritt(f.lpL, f.zll, schritt(f.hpL, f.zhl, l)), schritt(f.lpR, f.zlr, schritt(f.hpR, f.zhr, r)));\n            }\n            if (m.fenster.n >= m.fensterLaenge) {\n                m.verlauf.push(auswerten(m.fenster).korrelation);\n                m.fenster = summenAnlegen();\n            }\n        }\n        m.pos = ende;\n        return m.pos >= m.n;\n    }\n    function messungAuswerten(m) {\n        if (m.fenster.n > m.fensterLaenge \/ 4) { m.verlauf.push(auswerten(m.fenster).korrelation); }\n        var gesamt = auswerten(m.gesamt);\n        var energie = gesamt.energie || 1;\n        var baender = BAENDER.map(function (b, i) {\n            var e = auswerten(m.filter[i].summen);\n            e.id = b.id; e.von = b.von; e.bis = Math.min(b.bis, Math.round(m.fs * 0.45));\n            e.anteil = 100 * e.energie \/ energie;\n            return e;\n        });\n        var unter = m.verlauf.filter(function (k) { return k < 0; }).length;\n        var mono = m.kanaeleAnzahl < 2 || gesamt.korrelation > 0.99999 && gesamt.seite_db < -60;\n        return {\n            fs: m.fs, dauer: m.n \/ m.fs, kanaele: m.kanaeleAnzahl, mono: mono,\n            korrelation: gesamt.korrelation, seite_db: gesamt.seite_db, mono_db: gesamt.mono_db,\n            balance_db: gesamt.balance_db, rms_l_db: gesamt.rms_l_db, rms_r_db: gesamt.rms_r_db,\n            spitze_l_db: db(m.spitzeL), spitze_r_db: db(m.spitzeR),\n            baender: baender, verlauf: m.verlauf, fenster_s: FENSTER_S,\n            unter_null: m.verlauf.length ? 100 * unter \/ m.verlauf.length : 0,\n            kleinste: m.verlauf.length ? Math.min.apply(null, m.verlauf) : gesamt.korrelation\n        };\n    }\n    function analysiere(kanaele, fs) {\n        var m = messungAnlegen(kanaele, fs);\n        while (!messungSchritt(m, 1 << 20)) { \/* alles auf einmal *\/ }\n        return messungAuswerten(m);\n    }\n\n    \/\/ Befunde: Titel || Erklaerung, Art bestimmt die Farbe der Kante.\n    function befunde(e) {\n        var aus = [];\n        function nimm(schluessel, art, werte) {\n            var roh = String(T['befund_' + schluessel] || ''), teil = roh.split(' || ');\n            aus.push({ id: schluessel, art: art, titel: text0(teil[0], werte), text: text0(teil[1] || '', werte) });\n        }\n        if (e.mono) { nimm('mono', 'ok', {}); return aus; }\n        if (e.korrelation < -0.05) {\n            nimm('gegenphase', 'fail', { k: zahl(e.korrelation, 2), mono: zahl(e.mono_db, 1) });\n        } else if (e.mono_db < -3) {\n            nimm('mono_verlust', 'warn', { mono: zahl(e.mono_db, 1), k: zahl(e.korrelation, 2) });\n        }\n        var tief = e.baender[0];\n        if (tief.anteil > 1 && tief.korrelation < 0.5) {\n            nimm('bass_breit', 'warn', { k: zahl(tief.korrelation, 2), hz: zahl(tief.bis, 0) });\n        }\n        if (e.seite_db > 0.5) {\n            nimm('sehr_breit', 'warn', { seite: zahl(e.seite_db, 1) });\n        }\n        if (Math.abs(e.balance_db) > 1) {\n            nimm(e.balance_db > 0 ? 'balance_links' : 'balance_rechts', 'warn', { db: zahl(Math.abs(e.balance_db), 1) });\n        }\n        if (e.dauer < 5) { nimm('kurz', 'warn', { s: zahl(e.dauer, 1) }); }\n        if (!aus.length) { nimm('gut', 'ok', { k: zahl(e.korrelation, 2), seite: zahl(e.seite_db, 1) }); }\n        return aus;\n    }\n    \/\/ KERN-ENDE --------------------------------------------------------------\n\n    function text0(vorlage, werte) {\n        return String(vorlage).replace(\/\\{(\\w+)\\}\/g, function (m, k) { return werte &#038;&#038; werte[k] !== undefined ? werte[k] : m; });\n    }\n    function text(schluessel, werte) { return text0(T[schluessel], werte); }\n    function zahl(x, stellen, plus) {\n        if (typeof x !== 'number' || isNaN(x)) { return '\u2013'; }\n        if (!isFinite(x)) { return x > 0 ? '\u221e' : '\u2212\u221e'; }\n        var s = x.toFixed(stellen);\n        if (parseFloat(s) === 0) { s = Math.abs(parseFloat(s)).toFixed(stellen); }\n        else if (s.charAt(0) === '-') { s = '\u2212' + s.slice(1); }\n        else if (plus) { s = '+' + s; }\n        return s.replace('.', T.dezimal);\n    }\n    function dauerText(sek) {\n        var m = Math.floor(sek \/ 60), s = sek - 60 * m;\n        return m + ':' + (s < 10 ? '0' : '') + zahl(s, 1);\n    }\n    function el(id) { return document.getElementById(id); }\n\n    var ausgabe = el('sk-ausgabe'), status = el('sk-status'), statusText = el('sk-status-text'), fortschritt = el('sk-fortschritt');\n    var letztes = null;\n\n    function zeigeStatus(t, anteil) {\n        if (!status) { return; }\n        status.hidden = false;\n        statusText.textContent = t;\n        fortschritt.style.width = Math.round(100 * (anteil || 0)) + '%';\n    }\n    function fehlerZeigen(t) {\n        if (status) { status.hidden = true; }\n        ausgabe.textContent = '';\n        var p = document.createElement('p');\n        p.className = 'sk-befund sk-b-fail';\n        p.textContent = t;\n        ausgabe.appendChild(p);\n    }\n\n    function kachel(name, wert, einheit, klasse) {\n        var d = document.createElement('div'), n = document.createElement('div'), w = document.createElement('div');\n        d.className = 'sk-kachel'; n.className = 'sk-kachel-name'; w.className = 'sk-kachel-wert';\n        n.textContent = name;\n        w.textContent = wert;\n        w.setAttribute('data-kachel', klasse || name);\n        if (einheit) {\n            var e = document.createElement('span');\n            e.className = 'sk-einheit';\n            e.textContent = einheit;\n            w.appendChild(e);\n        }\n        d.appendChild(n); d.appendChild(w);\n        return d;\n    }\n\n    function verlaufZeichnen(e) {\n        var c = el('sk-verlauf');\n        if (!c || !e || !e.verlauf.length) { return; }\n        var breite = Math.max(320, c.clientWidth || 640), hoehe = 120, dpr = window.devicePixelRatio || 1;\n        c.width = Math.round(breite * dpr); c.height = Math.round(hoehe * dpr);\n        c.style.height = hoehe + 'px';\n        var g = c.getContext('2d');\n        if (!g) { return; }\n        g.setTransform(dpr, 0, 0, dpr, 0, 0);\n        var stil = window.getComputedStyle(document.documentElement);\n        var linie = (stil.getPropertyValue('--border') || '#2a2a35').trim() || '#2a2a35';\n        var akzent = (stil.getPropertyValue('--accent') || '#2ba6df').trim() || '#2ba6df';\n        var schlecht = (stil.getPropertyValue('--fail') || '#ff7b72').trim() || '#ff7b72';\n        g.clearRect(0, 0, breite, hoehe);\n        function y(k) { return hoehe \/ 2 - k * (hoehe \/ 2 - 6); }\n        g.strokeStyle = linie; g.lineWidth = 1;\n        [1, 0.5, 0, -0.5, -1].forEach(function (k) {\n            g.beginPath(); g.moveTo(0, y(k) + 0.5); g.lineTo(breite, y(k) + 0.5); g.stroke();\n        });\n        var n = e.verlauf.length;\n        for (var i = 0; i < n; i++) {\n            var x0 = breite * i \/ n, x1 = breite * (i + 1) \/ n, k = e.verlauf[i];\n            g.fillStyle = k < 0 ? schlecht : akzent;\n            var oben = Math.min(y(k), y(0)), hoch = Math.max(1, Math.abs(y(k) - y(0)));\n            g.fillRect(x0, oben, Math.max(1, x1 - x0), hoch);\n        }\n        g.strokeStyle = linie; g.beginPath(); g.moveTo(0, y(0) + 0.5); g.lineTo(breite, y(0) + 0.5); g.stroke();\n    }\n\n    function darstellen(e, info) {\n        letztes = { e: e, info: info };\n        ausgabe.textContent = '';\n\n        var kopf = document.createElement('p');\n        kopf.className = 'sk-klein';\n        kopf.style.margin = '0 0 10px';\n        kopf.textContent = text('datei_satz', {\n            name: info.name || '', dauer: dauerText(e.dauer), rate: zahl(e.fs \/ 1000, 1),\n            kanaele: e.kanaele === 1 ? T.kanal_mono : (e.kanaele === 2 ? T.kanal_stereo : text('kanal_mehr', { n: e.kanaele }))\n        });\n        ausgabe.appendChild(kopf);\n\n        var k = document.createElement('div');\n        k.className = 'sk-kacheln';\n        k.appendChild(kachel(T.k_korrelation, zahl(e.korrelation, 2, true), '', 'k_korrelation'));\n        k.appendChild(kachel(T.k_seite, zahl(e.seite_db, 1, true), 'dB', 'k_seite'));\n        k.appendChild(kachel(T.k_mono, zahl(e.mono_db, 1, true), 'dB', 'k_mono'));\n        k.appendChild(kachel(T.k_balance, zahl(e.balance_db, 1, true), 'dB', 'k_balance'));\n        ausgabe.appendChild(k);\n\n        var hb = document.createElement('div');\n        hb.className = 'sk-h';\n        hb.textContent = T.h_befunde;\n        ausgabe.appendChild(hb);\n        befunde(e).forEach(function (b) {\n            var d = document.createElement('div');\n            d.className = 'sk-befund sk-b-' + b.art;\n            var t = document.createElement('b');\n            t.textContent = b.titel;\n            d.appendChild(t);\n            if (b.text) {\n                var p = document.createElement('div');\n                p.className = 'sk-klein';\n                p.style.marginTop = '4px';\n                p.textContent = b.text;\n                d.appendChild(p);\n            }\n            ausgabe.appendChild(d);\n        });\n\n        var ht = document.createElement('div');\n        ht.className = 'sk-h';\n        ht.textContent = T.h_baender;\n        ausgabe.appendChild(ht);\n        var wrap = document.createElement('div');\n        wrap.className = 'sk-tabelle';\n        var tab = document.createElement('table');\n        var thead = document.createElement('thead'), tr = document.createElement('tr');\n        [T.sp_band, T.sp_korrelation, T.sp_seite, T.sp_mono, T.sp_anteil].forEach(function (s) {\n            var th = document.createElement('th');\n            th.textContent = s;\n            tr.appendChild(th);\n        });\n        thead.appendChild(tr);\n        tab.appendChild(thead);\n        var tbody = document.createElement('tbody');\n        tbody.id = 'sk-baender';\n        e.baender.forEach(function (b) {\n            var z = document.createElement('tr');\n            [[text('band_' + b.id, { von: zahl(b.von, 0), bis: zahl(b.bis, 0) }), true], [zahl(b.korrelation, 2, true)],\n             [zahl(b.seite_db, 1, true)], [zahl(b.mono_db, 1, true)], [zahl(b.anteil, 1)]].forEach(function (w) {\n                var td = document.createElement('td');\n                td.textContent = w[0];\n                if (w[1]) { td.className = 'sk-name'; }\n                z.appendChild(td);\n            });\n            tbody.appendChild(z);\n        });\n        tab.appendChild(tbody);\n        wrap.appendChild(tab);\n        ausgabe.appendChild(wrap);\n\n        var hv = document.createElement('div');\n        hv.className = 'sk-h';\n        hv.textContent = T.h_verlauf;\n        ausgabe.appendChild(hv);\n        var c = document.createElement('canvas');\n        c.id = 'sk-verlauf';\n        c.setAttribute('data-mp-mask', '');\n        ausgabe.appendChild(c);\n        var hinweis = document.createElement('p');\n        hinweis.className = 'sk-klein';\n        hinweis.style.margin = '8px 0 0';\n        hinweis.textContent = text('verlauf_hinweis', {\n            fenster: zahl(e.fenster_s, 1), unter: zahl(e.unter_null, 0), kleinste: zahl(e.kleinste, 2, true)\n        });\n        ausgabe.appendChild(hinweis);\n        verlaufZeichnen(e);\n        return e;\n    }\n\n    \/\/ --- Datei lesen ---------------------------------------------------------\n    \/\/ --- Dateien lesen -------------------------------------------------------\n    \/\/ WAV und AIFF werden selbst gelesen: so bleibt jeder Abtastwert, wie er in\n    \/\/ der Datei steht, und der Browser rechnet nicht auf seine eigene Rate um.\n    function ascii(dv, o, l) {\n        var s = '';\n        for (var i = 0; i < l &#038;&#038; o + i < dv.byteLength; i++) { s += String.fromCharCode(dv.getUint8(o + i)); }\n        return s;\n    }\n\n    function pcmZuKanaele(puffer, start, laenge, kanaele, bytes, art, kleinEndian) {\n        var rahmen = Math.floor(laenge \/ (bytes * kanaele));\n        var raus = [], c, i;\n        for (c = 0; c < kanaele; c++) { raus.push(new Float32Array(rahmen)); }\n        var ausgerichtet = kleinEndian &#038;&#038; (art === 'int' &#038;&#038; (bytes === 2 || bytes === 4) || art === 'float');\n        if (ausgerichtet) {\n            var stueck = puffer.slice(start, start + rahmen * bytes * kanaele);\n            var ansicht = art === 'float' ? (bytes === 4 ? new Float32Array(stueck) : new Float64Array(stueck))\n                : (bytes === 2 ? new Int16Array(stueck) : new Int32Array(stueck));\n            var teiler = art === 'float' ? 1 : (bytes === 2 ? 32768 : 2147483648);\n            for (c = 0; c < kanaele; c++) {\n                var ziel = raus[c];\n                for (i = 0; i < rahmen; i++) { ziel[i] = ansicht[i * kanaele + c] \/ teiler; }\n            }\n            return raus;\n        }\n        var dv = new DataView(puffer, start, rahmen * bytes * kanaele);\n        var u8 = new Uint8Array(puffer, start, rahmen * bytes * kanaele);\n        var o = 0;\n        for (i = 0; i < rahmen; i++) {\n            for (c = 0; c < kanaele; c++) {\n                var v;\n                if (art === 'float') { v = bytes === 4 ? dv.getFloat32(o, kleinEndian) : dv.getFloat64(o, kleinEndian); }\n                else if (bytes === 1) { v = kleinEndian ? (u8[o] - 128) \/ 128 : dv.getInt8(o) \/ 128; }\n                else if (bytes === 2) { v = dv.getInt16(o, kleinEndian) \/ 32768; }\n                else if (bytes === 3) {\n                    var w = kleinEndian ? (u8[o] | (u8[o + 1] << 8) | (u8[o + 2] << 16)) : ((u8[o] << 16) | (u8[o + 1] << 8) | u8[o + 2]);\n                    if (w &#038; 0x800000) { w -= 0x1000000; }\n                    v = w \/ 8388608;\n                } else { v = dv.getInt32(o, kleinEndian) \/ 2147483648; }\n                raus[c][i] = v;\n                o += bytes;\n            }\n        }\n        return raus;\n    }\n\n    function wavLesen(puffer) {\n        var dv = new DataView(puffer), n = puffer.byteLength, o = 12, fmt = null, ds64 = null;\n        while (o + 8 <= n) {\n            var id = ascii(dv, o, 4), groesse = dv.getUint32(o + 4, true);\n            if (id === 'ds64' &#038;&#038; groesse >= 16) {\n                ds64 = dv.getUint32(o + 16, true) + dv.getUint32(o + 20, true) * 4294967296;\n            } else if (id === 'fmt ') {\n                var tag = dv.getUint16(o + 8, true);\n                if (tag === 0xFFFE && groesse >= 26) { tag = dv.getUint16(o + 32, true); }\n                fmt = { tag: tag, kanaele: dv.getUint16(o + 10, true), rate: dv.getUint32(o + 12, true), bits: dv.getUint16(o + 22, true) };\n            } else if (id === 'data') {\n                if (!fmt) { return { fehler: 'fmt' }; }\n                var laenge = (groesse === 0xFFFFFFFF && ds64 !== null) ? ds64 : groesse;\n                laenge = Math.min(laenge, n - o - 8);\n                var bytes = fmt.bits \/ 8;\n                var art = fmt.tag === 1 ? 'int' : (fmt.tag === 3 ? 'float' : null);\n                if (!art || (art === 'int' && [1, 2, 3, 4].indexOf(bytes) === -1) || (art === 'float' && bytes !== 4 && bytes !== 8) || !fmt.kanaele) {\n                    return { fehler: 'tag ' + fmt.tag + ', ' + fmt.bits + ' bit' };\n                }\n                return { format: 'WAV', rate: fmt.rate, bits: fmt.bits, gleitkomma: art === 'float',\n                    kanaele: pcmZuKanaele(puffer, o + 8, laenge, fmt.kanaele, bytes, art, true) };\n            }\n            if (groesse === 0xFFFFFFFF) { break; }\n            o += 8 + groesse + (groesse % 2);\n        }\n        return { fehler: 'data' };\n    }<\/p>\n<p>    function erweitert80(dv, o) {\n        var exp = dv.getUint16(o, false) & 0x7FFF, hi = dv.getUint32(o + 2, false), lo = dv.getUint32(o + 6, false);\n        if (!exp && !hi && !lo) { return 0; }\n        return (hi * 4294967296 + lo) * Math.pow(2, exp - 16383 - 63);\n    }<\/p>\n<p>    function aiffLesen(puffer, aifc) {\n        var dv = new DataView(puffer), n = puffer.byteLength, o = 12, comm = null;\n        while (o + 8 <= n) {\n            var id = ascii(dv, o, 4), groesse = dv.getUint32(o + 4, false);\n            if (id === 'COMM') {\n                comm = { kanaele: dv.getUint16(o + 8, false), bits: dv.getUint16(o + 14, false), rate: Math.round(erweitert80(dv, o + 16)), art: 'NONE' };\n                if (aifc &#038;&#038; groesse >= 22) { comm.art = ascii(dv, o + 26, 4); }\n            } else if (id === 'SSND') {\n                if (!comm) { return { fehler: 'COMM' }; }\n                var versatz = dv.getUint32(o + 8, false), start = o + 16 + versatz;\n                var laenge = Math.min(groesse - 8 - versatz, n - start);\n                var art = comm.art, bytes = Math.ceil(comm.bits \/ 8);\n                if (art === 'NONE' || art === 'twos') {\n                    return { format: 'AIFF', rate: comm.rate, bits: comm.bits, kanaele: pcmZuKanaele(puffer, start, laenge, comm.kanaele, bytes, 'int', false) };\n                }\n                if (art === 'sowt') {\n                    return { format: 'AIFF', rate: comm.rate, bits: comm.bits, kanaele: pcmZuKanaele(puffer, start, laenge, comm.kanaele, bytes, 'int', true) };\n                }\n                if (art === 'fl32' || art === 'FL32' || art === 'fl64' || art === 'FL64') {\n                    return { format: 'AIFF', rate: comm.rate, bits: art.slice(2) === '32' ? 32 : 64, gleitkomma: true,\n                        kanaele: pcmZuKanaele(puffer, start, laenge, comm.kanaele, art.slice(2) === '32' ? 4 : 8, 'float', false) };\n                }\n                return { fehler: art };\n            }\n            o += 8 + groesse + (groesse % 2);\n        }\n        return { fehler: 'SSND' };\n    }<\/p>\n<p>    \/\/ Abtastrate komprimierter Formate aus dem Kopf, damit der Decoder des\n    \/\/ Browsers nicht auf eine fremde Rate umrechnet.\n    function kopfLesen(puffer) {\n        var n = puffer.byteLength, dv = new DataView(puffer);\n        var b = new Uint8Array(puffer, 0, Math.min(n, 4 << 20));\n        var k4 = ascii(dv, 0, 4);\n        if (k4 === 'fLaC' &#038;&#038; n > 22) {\n            return { format: 'FLAC', rate: (b[18] << 12) | (b[19] << 4) | (b[20] >> 4), kanaeleKopf: ((b[20] >> 1) & 7) + 1, bits: (((b[20] & 1) << 4) | (b[21] >> 4)) + 1 };\n        }\n        if (k4 === 'OggS' && n > 64) {\n            var d = 27 + b[26];\n            if (ascii(dv, d + 1, 6) === 'vorbis' && b[d] === 1) { return { format: 'Ogg Vorbis', rate: dv.getUint32(d + 12, true), kanaeleKopf: b[d + 11] }; }\n            if (ascii(dv, d, 8) === 'OpusHead') { return { format: 'Opus', rate: 48000, kanaeleKopf: b[d + 9] }; }\n            if (ascii(dv, d + 1, 4) === 'FLAC' && ascii(dv, d + 9, 4) === 'fLaC') {\n                var s = d + 17;\n                return { format: 'Ogg FLAC', rate: (b[s + 10] << 12) | (b[s + 11] << 4) | (b[s + 12] >> 4) };\n            }\n            return { format: 'Ogg', rate: null };\n        }\n        if (ascii(dv, 4, 4) === 'ftyp') {\n            var suchen = function (a, bb, c, dd) {\n                for (var i = 4; i + 36 < b.length; i++) {\n                    if (b[i] === a &#038;&#038; b[i + 1] === bb &#038;&#038; b[i + 2] === c &#038;&#038; b[i + 3] === dd) { return i - 4; }\n                }\n                return -1;\n            };\n            var box = suchen(0x6D, 0x70, 0x34, 0x61), name = 'AAC';\n            if (box < 0) { box = suchen(0x61, 0x6C, 0x61, 0x63); name = 'ALAC'; }\n            var rate = box >= 0 ? dv.getUint16(box + 32, false) : 0;\n            return { format: name, rate: rate >= 8000 ? rate : null };\n        }\n        var start = 0;\n        if (ascii(dv, 0, 3) === 'ID3' && n > 10) {\n            start = 10 + ((b[6] & 0x7f) << 21 | (b[7] &#038; 0x7f) << 14 | (b[8] &#038; 0x7f) << 7 | (b[9] &#038; 0x7f)) + ((b[5] &#038; 0x10) ? 10 : 0);\n        }\n        var bis = Math.min(b.length - 4, start + 65536);\n        for (var j = start; j < bis; j++) {\n            if (b[j] !== 0xFF || (b[j + 1] &#038; 0xE0) !== 0xE0) { continue; }\n            var version = (b[j + 1] >> 3) & 3, schicht = (b[j + 1] >> 1) & 3;\n            if (schicht === 0 && (b[j + 1] & 0xF6) === 0xF0) {\n                var idx = (b[j + 2] >> 2) & 15;\n                var raten = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];\n                if (idx < raten.length) { return { format: 'AAC', rate: raten[idx] }; }\n                continue;\n            }\n            var ri = (b[j + 2] >> 2) & 3, bri = b[j + 2] >> 4;\n            if (version === 1 || schicht === 0 || ri === 3 || bri === 15 || bri === 0) { continue; }\n            var basis = [44100, 48000, 32000][ri];\n            return { format: schicht === 1 ? 'MP3' : 'MPEG', rate: version === 3 ? basis : (version === 2 ? basis \/ 2 : basis \/ 4), kanaeleKopf: (b[j + 3] >> 6) === 3 ? 1 : 2 };\n        }\n        return { format: null, rate: null };\n    }\n    \/\/ Komprimierte Formate uebernimmt der Browser; die Rate stammt aus dem Kopf,\n    \/\/ damit Web Audio nicht auf seine eigene Rate umrechnet.\n    function dekodieren(puffer, rate) {\n        return new Promise(function (ok, fehler) {\n            var Ctx = window.OfflineAudioContext || window.webkitOfflineAudioContext;\n            if (!Ctx) { fehler(new Error('webaudio')); return; }\n            var ctx;\n            try { ctx = new Ctx(2, 1, rate); } catch (e) {\n                try { ctx = new Ctx(2, 1, 48000); } catch (e2) { fehler(new Error('webaudio')); return; }\n            }\n            var fertig = false;\n            function gut(buf) { if (!fertig) { fertig = true; ok(buf); } }\n            function schlecht(e) { if (!fertig) { fertig = true; fehler(e || new Error('dekodieren')); } }\n            try {\n                var p = ctx.decodeAudioData(puffer, gut, schlecht);\n                if (p && typeof p.then === 'function') { p.then(gut, schlecht); }\n            } catch (e) { schlecht(e); }\n        });\n    }<\/p>\n<p>    var tick = typeof MessageChannel !== 'undefined' ? new MessageChannel() : null, schlange = [];\n    if (tick) { tick.port1.onmessage = function () { var f = schlange.shift(); if (f) { f(); } }; }\n    function spaeter(f) { if (tick) { schlange.push(f); tick.port2.postMessage(0); } else { setTimeout(f, 0); } }<\/p>\n<p>    function messenAsync(kanaele, fs) {\n        return new Promise(function (ok, fehler) {\n            var m;\n            try { m = messungAnlegen(kanaele, fs); } catch (e) { fehler(e); return; }\n            function weiter() {\n                try {\n                    var fertig = messungSchritt(m, STUECK);\n                    zeigeStatus(T.status_messen, m.n ? m.pos \/ m.n : 1);\n                    if (fertig) { ok(messungAuswerten(m)); return; }\n                } catch (e) { fehler(e); return; }\n                spaeter(weiter);\n            }\n            spaeter(weiter);\n        });\n    }<\/p>\n<p>    \/\/ WAV und AIFF selbst lesen, alles andere ueber Web Audio.\n    function einlesen(puffer) {\n        var dv = new DataView(puffer), k4 = ascii(dv, 0, 4), art = ascii(dv, 8, 4);\n        if ((k4 === 'RIFF' || k4 === 'RF64' || k4 === 'BW64') && art === 'WAVE') {\n            var w = wavLesen(puffer);\n            if (!w.fehler) { return Promise.resolve(w); }\n            return Promise.reject({ format: w.fehler });\n        }\n        if (k4 === 'FORM' && (art === 'AIFF' || art === 'AIFC')) {\n            var a = aiffLesen(puffer, art === 'AIFC');\n            if (!a.fehler) { return Promise.resolve(a); }\n        }\n        var kopf = kopfLesen(puffer);\n        var rate = kopf.rate && kopf.rate >= 3000 && kopf.rate <= 768000 ? kopf.rate : 48000;\n        return dekodieren(puffer, rate).then(function (buf) {\n            var kanaele = [];\n            for (var c = 0; c < buf.numberOfChannels; c++) { kanaele.push(buf.getChannelData(c)); }\n            return { format: kopf.format, rate: buf.sampleRate, kanaele: kanaele };\n        });\n    }\n\n    function verarbeitenPuffer(puffer, name) {\n        zeigeStatus(T.status_dekodieren, 0);\n        return einlesen(puffer).then(function (d) {\n            var kanaele = d.kanaele;\n            if (!kanaele.length || !kanaele[0].length) { throw { leer: true }; }\n            return messenAsync(kanaele, d.rate).then(function (e) {\n                status.hidden = true;\n                return darstellen(e, { name: name, format: d.format });\n            });\n        }).catch(function (f) {\n            if (window.LW_TEST &#038;&#038; window.LW_TEST.SK) { window.LW_TEST.SK.letzterFehler = f; }\n            if (f &#038;&#038; f.leer) { fehlerZeigen(T.fehler_leer); }\n            else if (f &#038;&#038; f.format) { fehlerZeigen(text('fehler_format', { detail: f.format })); }\n            else if (f &#038;&#038; f.message === 'webaudio') { fehlerZeigen(T.fehler_webaudio); }\n            else if (f &#038;&#038; (f.name === 'RangeError' || \/memory|allocation\/i.test(String(f.message || '')))) { fehlerZeigen(T.fehler_speicher); }\n            else { fehlerZeigen(T.fehler_dekodieren); }\n            return null;\n        });\n    }\n\n    function dateiNehmen(datei) {\n        if (!datei) { return; }\n        zeigeStatus(T.status_lesen, 0);\n        var leser = new FileReader();\n        leser.onload = function () { verarbeitenPuffer(leser.result, datei.name); };\n        leser.onerror = function () { fehlerZeigen(T.fehler_dekodieren); };\n        try { leser.readAsArrayBuffer(datei); } catch (x) { fehlerZeigen(T.fehler_speicher); }\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.SK = {\n        T: T, BAENDER: BAENDER, analysiere: analysiere, befunde: befunde, biquad: biquad, bandFiltern: bandFiltern,\n        auswerten: auswerten, summenAnlegen: summenAnlegen, summenNehmen: summenNehmen, zahl: zahl, text: text,\n        darstellen: darstellen, verarbeitenPuffer: verarbeitenPuffer, einlesen: einlesen, wavLesen: wavLesen,\n        aiffLesen: aiffLesen, kopfLesen: kopfLesen, dauerText: dauerText, db: db\n    };\n\n    var zone = el('sk-zone'), eingabe = el('sk-datei'), knopf = el('sk-knopf');\n    if (!zone || !eingabe || !ausgabe) { return; }\n    knopf.addEventListener('click', function () { eingabe.click(); });\n    eingabe.addEventListener('change', function () { dateiNehmen(eingabe.files &#038;&#038; eingabe.files[0]); eingabe.value = ''; });\n    ['dragenter', 'dragover'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.add('sk-ueber'); });\n    });\n    ['dragleave', 'drop'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.remove('sk-ueber'); });\n    });\n    zone.addEventListener('drop', function (ev) {\n        var f = ev.dataTransfer &#038;&#038; ev.dataTransfer.files &#038;&#038; ev.dataTransfer.files[0];\n        dateiNehmen(f);\n    });\n    var warten = null;\n    window.addEventListener('resize', function () {\n        clearTimeout(warten);\n        warten = setTimeout(function () { if (letztes) { verlaufZeichnen(letztes.e); } }, 150);\n    });\n    if (window.MutationObserver) {\n        new MutationObserver(function () { if (letztes) { verlaufZeichnen(letztes.e); } })\n            .observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });\n    }\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reads an audio file in the browser and measures the correlation between the left and right channel, the level of the side signal against the mid, the loss of a mono sum and the channel balance, in total and in three frequency bands, plus the correlation over time.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":38,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92901],"class_list":["post-19924","page","type-page","status-publish","hentry","tag-music-production"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Reads an audio file in the browser and measures the correlation between the left and right channel, the level of the side signal against the mid, the loss of a mono sum and the channel balance, in total and in three frequency bands, plus the correlation over time.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/stereo-correlation-mid-side-meter\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/stereo-correlation-mid-side-meter\\\/\",\"name\":\"Stereo Correlation and Mid\\\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-17T18:06:47+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/stereo-correlation-mid-side-meter\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/stereo-correlation-mid-side-meter\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/stereo-correlation-mid-side-meter\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Stereo Correlation and Mid\\\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/","og_locale":"en_US","og_type":"article","og_title":"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog","og_description":"Reads an audio file in the browser and measures the correlation between the left and right channel, the level of the side signal against the mid, the loss of a mono sum and the channel balance, in total and in three frequency bands, plus the correlation over time.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/","name":"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-17T18:06:47+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/stereo-correlation-mid-side-meter\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/"},{"@type":"ListItem","position":3,"name":"Stereo Correlation and Mid\/Side Meter: correlation per band, side share, mono compatibility and channel balance from an audio file"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/19924","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=19924"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/19924\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/38"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=19924"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=19924"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}