{"id":20241,"date":"2026-09-23T21:37:58","date_gmt":"2026-09-23T19:37:58","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/werkzeuge\/time-offset-polarity-checker-two-tracks\/"},"modified":"2026-09-23T21:59:45","modified_gmt":"2026-09-23T19:59:45","slug":"time-offset-polarity-checker-two-tracks","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/","title":{"rendered":"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren"},"content":{"rendered":"<div class=\"lw-vp\" id=\"vp-wurzel\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<style>\n.lw-vp { --vp-warn: #e8a33d; }\n:root[data-theme=\"light\"] .lw-vp { --vp-warn: #8f5300; }\n.lw-vp .vp-zonen { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n.lw-vp .vp-zone { border: 2px dashed var(--border, #2a2a35); border-radius: 8px; padding: 18px; text-align: center; min-width: 0; }\n.lw-vp .vp-zone.vp-ueber { border-color: var(--accent, #2ba6df); }\n.lw-vp .vp-zone-name { margin: 0 0 10px; color: var(--text-primary, #e8e8ee); font-weight: 700; }\n.lw-vp .vp-datei-name { font-family: monospace; font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); margin: 10px 0 0; overflow-wrap: anywhere; min-height: 1.2em; }\n.lw-vp .vp-waehlen { background: transparent; color: var(--text-primary, #e8e8ee); border: 1px solid var(--border, #2a2a35); padding: 9px 16px; border-radius: 6px; cursor: pointer; font-size: 0.9rem; }\n.lw-vp .vp-kacheln { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 4px 0; }\n.lw-vp .vp-kachel { background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 11px 14px; min-width: 0; }\n.lw-vp .vp-kachel-name { font-size: 0.74rem; color: var(--text-secondary, #a0a0b0); text-transform: uppercase; letter-spacing: 0.4px; }\n.lw-vp .vp-kachel-wert { font-family: monospace; font-size: 1.4rem; font-weight: 700; color: var(--text-primary, #e8e8ee); line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.lw-vp .vp-urteil { border-radius: 8px; padding: 12px 15px; margin-top: 14px; border: 1px solid var(--border, #2a2a35); background: var(--bg-body, #14141a); }\n.lw-vp .vp-urteil-kopf { font-weight: 700; color: var(--text-primary, #e8e8ee); margin-bottom: 4px; }\n.lw-vp .vp-u-gut .vp-urteil-kopf { color: var(--ok, #7ee787); }\n.lw-vp .vp-u-tun .vp-urteil-kopf { color: var(--vp-warn); }\n.lw-vp .vp-urteil p { margin: 6px 0 0; }\n.lw-vp .vp-befehl { font-family: monospace; font-size: 0.84rem; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 10px 12px; margin-top: 10px; overflow-wrap: anywhere; color: var(--text-primary, #e8e8ee); }\n.lw-vp .vp-tabelle { overflow-x: auto; margin-top: 6px; }\n.lw-vp table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }\n.lw-vp th, .lw-vp td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #2a2a35); vertical-align: top; }\n.lw-vp th { color: var(--text-primary, #e8e8ee); }\n.lw-vp td { color: var(--text-primary, #e8e8ee); }\n.lw-vp td.vp-wert { font-family: monospace; color: var(--text-secondary, #a0a0b0); white-space: nowrap; }\n.lw-vp .vp-h { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 24px 0 8px; }\n.lw-vp .vp-klein { font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); line-height: 1.55; }\n.lw-vp .vp-knopf { background: transparent; color: var(--text-secondary, #a0a0b0); border: 1px solid var(--border, #2a2a35); padding: 9px 14px; border-radius: 6px; cursor: pointer; font-size: 0.9rem; margin-top: 12px; }\n.lw-vp .vp-fehler { color: var(--fehler, #f0857a); font-size: 0.88rem; margin-top: 12px; }\n.lw-vp a { color: var(--accent, #2ba6df); }\n@media (max-width: 600px) {\n    .lw-vp .vp-zonen { grid-template-columns: 1fr; }\n    .lw-vp .vp-kacheln { grid-template-columns: 1fr 1fr; gap: 8px; }\n    .lw-vp .vp-kachel-wert { font-size: 1.15rem; }\n    .lw-vp table.vp-karten thead { display: none; }\n    .lw-vp table.vp-karten tr { display: block; padding: 8px 0; border-bottom: 1px solid var(--border, #2a2a35); }\n    .lw-vp table.vp-karten td { display: block; border: none; padding: 1px 0; }\n    .lw-vp table.vp-karten td.vp-wert { white-space: normal; overflow-wrap: anywhere; }\n    .lw-vp table.vp-karten td:first-child { font-weight: 700; }\n    .lw-vp table.vp-karten td[data-name]::before { content: attr(data-name) \": \"; color: var(--text-secondary, #a0a0b0); font-family: inherit; }\n}\n<\/style>\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 18px;\">Misst, um wie viel eine zweite Spur gegen\u00fcber einer ersten verschoben ist und ob ihre Polarit\u00e4t umgekehrt ist: zwei Mikrofone an einer Quelle, DI und Verst\u00e4rker eines Basses, eine Spur vor und nach einem Plugin mit Latenz. Dazu zeigt es, was die Summe beider Spuren gesamt und unter 150\u00a0Hz gewinnt oder verliert, auch bei Kick und Bass, die keine gemeinsame Quelle haben. Die Dateien werden im Browser gelesen und nicht hochgeladen.<\/p>\n<div class=\"vp-zonen\">\n<div id=\"vp-zone-a\" class=\"vp-zone\">\n<p class=\"vp-zone-name\">Spur A (Bezug)<\/p>\n<p>            <button id=\"vp-knopf-a\" type=\"button\" class=\"vp-waehlen\">Datei w\u00e4hlen<\/button><br \/>\n            <input id=\"vp-datei-a\" type=\"file\" accept=\"audio\/*,.wav,.wave,.aif,.aiff,.aifc,.flac,.mp3,.m4a,.ogg,.opus\" hidden><\/p>\n<p id=\"vp-name-a\" class=\"vp-datei-name\" data-mp-mask>\n<\/p><\/div>\n<div id=\"vp-zone-b\" class=\"vp-zone\">\n<p class=\"vp-zone-name\">Spur B (wird verschoben)<\/p>\n<p>            <button id=\"vp-knopf-b\" type=\"button\" class=\"vp-waehlen\">Datei w\u00e4hlen<\/button><br \/>\n            <input id=\"vp-datei-b\" type=\"file\" accept=\"audio\/*,.wav,.wave,.aif,.aiff,.aifc,.flac,.mp3,.m4a,.ogg,.opus\" hidden><\/p>\n<p id=\"vp-name-b\" class=\"vp-datei-name\" data-mp-mask>\n<\/p><\/div>\n<\/p><\/div>\n<p class=\"vp-klein\" style=\"margin: 12px 0 0;\">Mit nur einer Stereodatei als Spur A wird links gegen rechts gemessen. WAV und AIFF werden Wert f\u00fcr Wert gelesen; FLAC, MP3, M4A, Ogg und Opus laufen \u00fcber den Decoder des Browsers.<\/p>\n<p>    <button id=\"vp-messen\" type=\"button\" class=\"button\" disabled style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 11px 22px; border-radius: 6px; font-weight: 700; cursor: pointer; margin-top: 14px;\">Messen<\/button><br \/>\n    <button id=\"vp-leeren\" type=\"button\" class=\"vp-knopf\" style=\"margin-left: 8px;\">Auswahl leeren<\/button><\/p>\n<div id=\"vp-status\" class=\"vp-klein\" data-mp-mask style=\"margin-top: 12px;\" aria-live=\"polite\"><\/div>\n<div id=\"vp-fehler\" class=\"vp-fehler\" data-mp-mask hidden><\/div>\n<div id=\"vp-ausgabe\" data-mp-mask style=\"margin-top: 18px;\" aria-live=\"polite\" hidden>\n<div id=\"vp-kacheln\" class=\"vp-kacheln\"><\/div>\n<div id=\"vp-urteil\" class=\"vp-urteil\"><\/div>\n<div class=\"vp-h\">Summe beider Spuren<\/div>\n<div class=\"vp-tabelle\">\n<table class=\"vp-karten\">\n<thead>\n<tr>\n<th>Fall<\/th>\n<th>Summe gesamt<\/th>\n<th>Unter 150\u00a0Hz<\/th>\n<th>Schw\u00e4chstes 100-ms-Fenster unter 150\u00a0Hz<\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"vp-summen\"><\/tbody>\n<\/table><\/div>\n<p id=\"vp-summe-hinweis\" class=\"vp-klein\" style=\"margin: 8px 0 0;\">\n<p>        <button id=\"vp-kopieren\" type=\"button\" class=\"vp-knopf\">Ergebnis kopieren<\/button><br \/>\n        <span id=\"vp-kopiert\" class=\"vp-klein\" style=\"margin-left: 10px;\"><\/span>\n    <\/div>\n<div class=\"vp-h\">Wie gemessen wird<\/div>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Aus bis zu 30\u00a0s gemeinsamem Material, ab 0,1\u00a0s nach dem Anfang, wird die Kreuzkorrelation beider Spuren f\u00fcr Verschiebungen bis \u00b1100\u00a0ms berechnet. Die Lage des Gipfels kommt aus einer gewei\u00dften Fassung (SCOT), in der jede Frequenz gleich z\u00e4hlt; so verschmieren tiefe T\u00f6ne und Nachhall den Gipfel nicht. Zwischenwerte liefert eine Sinc-Interpolation auf ein Tausendstel Wert. \u00dcbereinstimmung und Polarit\u00e4t stammen aus der gew\u00f6hnlichen normierten Korrelation an dieser Stelle; sie gewichtet nach Energie, so wie die Summe zu h\u00f6ren ist.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Die Tabelle rechnet die Summe beider Spuren, wie sie liegen, mit gedrehter Polarit\u00e4t von B und nach dem Verschieben. Unter 150\u00a0Hz filtert ein Butterworth-Tiefpass 4. Ordnung beide Spuren gleich. Das schw\u00e4chste 100-ms-Fenster z\u00e4hlt nur Stellen, an denen beide Spuren spielen (je h\u00f6chstens 20\u00a0dB unter ihrem lautesten Fenster); bei Kick und Bass ist das der Moment, in dem der Tiefbass am st\u00e4rksten ausl\u00f6scht.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Gedrehte Polarit\u00e4t kehrt jeden Wert um und wirkt auf alle Frequenzen gleich. Ein Versatz dagegen dreht die Phase je Frequenz verschieden: Bei 1\u00a0ms liegt die erste Ausl\u00f6schung bei 500\u00a0Hz, die n\u00e4chste bei 1,5\u00a0kHz. Deshalb ersetzt eine gedrehte Polarit\u00e4t kein Verschieben. Schall legt bei 20 \u00b0C in Luft 344 m\/s zur\u00fcck, 1\u00a0ms entspricht also 34,4 cm Abstand zwischen zwei Mikrofonen.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">In FL Studio dreht der Fruity Stereo Shaper die Polarit\u00e4t eines oder beider Kan\u00e4le und verz\u00f6gert einen Kanal gegen den anderen; den Ausgleich einer Mixer-Spur nimmt FL Studio laut Handbuch auch von Hand in Millisekunden oder Samples an, Samples sind dabei die feinste Einstellung.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Gepr\u00fcft an 21 Testf\u00e4llen mit bekanntem Versatz: Ganze und gebrochene Vers\u00e4tze trafen auf h\u00f6chstens 0,016 Werte, zwei Mikrofone mit Raumanteil und Rauschen (r = 0,32) auf 0,011 Werte, eine Snare oben und unten mit Hochpass am unteren Mikrofon als verschoben und verpolt. Ein Sinuston blieb mehrdeutig; Kick gegen Bass, Drums gegen Bass und unabh\u00e4ngiges Rauschen ergaben kein gemeinsames Signal. Nach dem vorgeschlagenen ffmpeg-Befehl lagen die Spuren in allen sieben nachgemessenen F\u00e4llen deckungsgleich, und die Summe traf die Vorhersage auf 0,1\u00a0dB. Im echten Browser (Chromium) ergab dieselbe Spur B als FLAC, MP3, AAC in M4A und Opus gegen die WAV-Fassung von A jeweils 64 Werte Versatz auf 0,002 Werte genau: Den Vorlauf der Encoder entfernt der Decoder, und Opus wird auf die Rate von A gebracht.<\/p>\n<div class=\"vp-h\">Artikel dazu<\/div>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Wie Sidechain-Kompression den Bass bei jedem Kick absenkt, statt beide gegeneinander zu verschieben, zeigt die Anleitung \u201e<a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/music-production-de\/tutorials-de-music-production-de\/sidechain-kompression-fl-studio-2026-schritt-fuer-schritt\/\">Sidechain-Kompression in FL Studio 2026<\/a>\u201c.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Kammfilter, Snare oben und unten sowie Kick innen und au\u00dfen misst der Artikel \u201e<span class=\"lw-artikel-geplant\">Versatz und Polarit\u00e4t zweier Spuren<\/span>\u201c.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Was Startphase, Stimmung, Hochpass und Ducking an der Summe von Kick und Bass im Tiefbass \u00e4ndern, misst der Artikel \u201e<span class=\"lw-artikel-geplant\">Kick und Bass im Tiefbass<\/span>\u201c.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Was eine Verz\u00f6gerung zwischen links und rechts in der Mono-Summe kostet, misst der Artikel \u201e<span class=\"lw-artikel-geplant\">Stereo-Verbreiterung<\/span>\u201c.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Wie viel Latenz ein linearphasiger EQ mitbringt, eine h\u00e4ufige Ursache f\u00fcr Versatz in parallelen Wegen, misst der Artikel \u201e<span class=\"lw-artikel-geplant\">Linearphasiger gegen minimalphasigen EQ<\/span>\u201c.<\/p>\n<p class=\"vp-klein\" style=\"margin: 20px 0 0;\">Quellen:<br \/>\n        <a href=\"https:\/\/www.image-line.com\/fl-studio-learning\/fl-studio-online-manual\/html\/mixer_trackprops.htm\" rel=\"noopener\">Image-Line: Mixer Track Effects (Plugin Delay Compensation)<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/www.image-line.com\/fl-studio-learning\/fl-studio-online-manual\/html\/plugins\/Fruity%20Stereo%20Shaper.htm\" rel=\"noopener\">Image-Line: Fruity Stereo Shaper<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/ffmpeg.org\/ffmpeg-filters.html\" rel=\"noopener\">ffmpeg Filters Documentation (adelay, atrim, aeval)<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/hyperphysics.gsu.edu\/hbase\/Sound\/souspe.html\" rel=\"noopener\">HyperPhysics: Speed of Sound<\/a>\n    <\/p>\n<p class=\"vp-klein\" style=\"font-size: 0.8rem; margin: 14px 0 0;\">Gesucht wird nur bis \u00b1100\u00a0ms; ein gr\u00f6\u00dferer Versatz ergibt \u201ekein gemeinsames Signal\u201c. Ein Versatz, der \u00fcber die Datei wandert, etwa bei verschiedenen Taktgebern zweier Ger\u00e4te, hat keine feste Lage; gemessen wird dann ein Mittel \u00fcber die ersten 30\u00a0s. Filter verz\u00f6gern selbst: Ein Tiefpass bei 5\u00a0kHz auf Spur B verschob die gemessene Lage im Test um 3,9 Werte, und genau diese Laufzeit gleicht das Verschieben mit aus.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';\n    const T = {\"dezimal\":\",\",\"einleitung\":\"Misst, um wie viel eine zweite Spur gegen\u00fcber einer ersten verschoben ist und ob ihre Polarit\u00e4t umgekehrt ist: zwei Mikrofone an einer Quelle, DI und Verst\u00e4rker eines Basses, eine Spur vor und nach einem Plugin mit Latenz. Dazu zeigt es, was die Summe beider Spuren gesamt und unter 150\u00a0Hz gewinnt oder verliert, auch bei Kick und Bass, die keine gemeinsame Quelle haben. Die Dateien werden im Browser gelesen und nicht hochgeladen.\",\"zone_a\":\"Spur A (Bezug)\",\"zone_b\":\"Spur B (wird verschoben)\",\"knopf_datei\":\"Datei w\u00e4hlen\",\"zone_hinweis\":\"Mit nur einer Stereodatei als Spur A wird links gegen rechts gemessen. WAV und AIFF werden Wert f\u00fcr Wert gelesen; FLAC, MP3, M4A, Ogg und Opus laufen \u00fcber den Decoder des Browsers.\",\"knopf_messen\":\"Messen\",\"knopf_leeren\":\"Auswahl leeren\",\"status_lesen\":\"Dateien werden gelesen \u2026\",\"status_messen\":\"Messung l\u00e4uft \u2026\",\"k_versatz\":\"Versatz\",\"k_werte\":\"In Werten\",\"k_polaritaet\":\"Polarit\u00e4t\",\"k_r\":\"\u00dcbereinstimmung r\",\"werte\":\"Werte\",\"pol_gleich\":\"gleich\",\"pol_gedreht\":\"gedreht\",\"pol_unklar\":\"unklar\",\"spaeter\":\"B liegt {ms} sp\u00e4ter als A\",\"frueher\":\"B liegt {ms} fr\u00fcher als A\",\"urteil_deckend\":\"Deckungsgleich\",\"urteil_text_deckend\":\"B liegt auf einen halben Wert genau unter A und hat dieselbe Polarit\u00e4t. Zu verschieben gibt es nichts.\",\"urteil_versatz\":\"{lage}\",\"urteil_text_versatz\":\"Um {werte} Werte verschoben, decken sich die Spuren. Der Befehl unten verschiebt B mit ffmpeg; in einer DAW l\u00e4sst sich die Spur ebenso um diese Zahl von Werten schieben.\",\"urteil_verpolt\":\"B ist verpolt\",\"urteil_text_verpolt\":\"Die Spuren liegen zeitlich richtig, aber B ist umgekehrt: Wo A nach oben schwingt, schwingt B nach unten. Mit gedrehter Polarit\u00e4t von B stimmt die Summe wieder.\",\"urteil_versatz_verpolt\":\"{lage}, dazu verpolt\",\"urteil_text_versatz_verpolt\":\"Um {werte} Werte verschoben und mit gedrehter Polarit\u00e4t decken sich die Spuren. Der Befehl unten erledigt beides.\",\"urteil_mehrdeutig\":\"Versatz nicht eindeutig\",\"urteil_text_mehrdeutig\":\"Mehrere Verschiebungen passen fast gleich gut. Das geschieht bei gleichbleibenden T\u00f6nen, deren Schwingung sich mit jeder Periode wiederholt; ein Abschnitt mit Eins\u00e4tzen oder Ger\u00e4uschanteil entscheidet die Frage.\",\"kandidaten\":\"In Frage kommen: {liste}.\",\"urteil_kein_bezug\":\"Kein gemeinsames Signal\",\"urteil_text_kein_bezug\":\"Die Spuren teilen keine Wellenform, etwa Kick und Bass oder zwei verschiedene Instrumente. Ein Versatz l\u00e4sst sich dann nicht messen. F\u00fcr die Summe z\u00e4hlt der Tiefbass: Die Tabelle zeigt, was sie unter 150\u00a0Hz so und mit gedrehter Polarit\u00e4t von B verliert.\",\"hinweis_schwach\":\"Die Wellenformen stimmen nur zum Teil \u00fcberein (r = {r}), etwa durch Raumanteil, Filter oder Verzerrung. Die Lage stammt aus der gewei\u00dften Korrelation und bleibt davon unber\u00fchrt; die Summe gewinnt durch das Verschieben entsprechend weniger.\",\"hinweis_unklar\":\"Ob B verpolt ist, entscheidet die Wellenform hier nicht (r = {r}): Filter verschieben tiefe Frequenzen anders als hohe. Welche Polarit\u00e4t die lautere Summe ergibt, steht in der Tabelle.\",\"hinweis_kerbe\":\"Solange der Versatz besteht, wirkt die Summe als Kammfilter mit der ersten Kerbe bei {hz} und weiteren bei jedem ungeraden Vielfachen davon. {ms} entsprechen {cm} Schallweg in Luft.\",\"hinweis_dekodiert\":\"Mindestens eine Datei lief \u00fcber den Decoder des Browsers und wurde mit {hz} dekodiert, der Rate des Vergleichs. Den Vorlauf von MP3 und AAC entfernt der Decoder, wenn die Datei ihn angibt; der Versatz bezieht sich dann auf den Klang selbst.\",\"hinweis_lr\":\"Gemessen wurde der linke gegen den rechten Kanal derselben Datei; B ist der rechte Kanal.\",\"befehl_hinweis\":\"Der Befehl nimmt B als b.wav und schreibt b_korrigiert.wav; atrim verschiebt nach vorn, adelay nach hinten, aeval dreht die Polarit\u00e4t.\",\"h_summe\":\"Summe beider Spuren\",\"sp_fall\":\"Fall\",\"sp_gesamt\":\"Summe gesamt\",\"sp_tief\":\"Unter 150\u00a0Hz\",\"sp_fenster\":\"Schw\u00e4chstes 100-ms-Fenster unter 150\u00a0Hz\",\"fall_jetzt\":\"wie sie liegen\",\"fall_gedreht\":\"B gedreht\",\"fall_verschoben\":\"B um {werte} Werte verschoben\",\"fall_verschoben_gedreht\":\"B verschoben und gedreht\",\"kaum_tief\":\"kaum Tiefbass\",\"summe_hinweis\":\"Pegel der Summe gegen die Summe der Einzelleistungen: +3\u00a0dB hei\u00dft gleich und deckungsgleich, 0\u00a0dB verh\u00e4lt sich wie zwei unabh\u00e4ngige Signale, negative Werte sind Ausl\u00f6schung. Gemessen \u00fcber {s}.\",\"knopf_kopieren\":\"Ergebnis kopieren\",\"kopiert\":\"kopiert\",\"kopieren_fehler\":\"Kopieren nicht m\u00f6glich\",\"bericht_kopf\":\"Versatz und Polarit\u00e4t\",\"fehler_format\":\"Eine der Dateien geh\u00f6rt zu keinem der hier gelesenen Formate: WAV, AIFF, FLAC, MP3, M4A, Ogg oder Opus.\",\"fehler_lesen\":\"Eine der Dateien lie\u00df sich nicht lesen oder dekodieren.\",\"fehler_kurz\":\"Zu wenig gemeinsames Material: n\u00f6tig sind mindestens 0,25\u00a0s.\",\"fehler_mono\":\"Nur Spur A ist gew\u00e4hlt, und sie ist mono. F\u00fcr links gegen rechts ist eine Stereodatei n\u00f6tig, sonst eine zweite Datei als Spur B.\",\"fehler_rate\":\"A und B haben verschiedene Abtastraten ({a} und {b}\u00a0Hz). Auf eine gemeinsame Rate gebracht, lassen sie sich vergleichen; sonst wandert der Versatz \u00fcber die Dauer der Datei.\",\"h_erklaerung\":\"Wie gemessen wird\",\"erkl_verfahren\":\"Aus bis zu 30\u00a0s gemeinsamem Material, ab 0,1\u00a0s nach dem Anfang, wird die Kreuzkorrelation beider Spuren f\u00fcr Verschiebungen bis \u00b1100\u00a0ms berechnet. Die Lage des Gipfels kommt aus einer gewei\u00dften Fassung (SCOT), in der jede Frequenz gleich z\u00e4hlt; so verschmieren tiefe T\u00f6ne und Nachhall den Gipfel nicht. Zwischenwerte liefert eine Sinc-Interpolation auf ein Tausendstel Wert. \u00dcbereinstimmung und Polarit\u00e4t stammen aus der gew\u00f6hnlichen normierten Korrelation an dieser Stelle; sie gewichtet nach Energie, so wie die Summe zu h\u00f6ren ist.\",\"erkl_summe\":\"Die Tabelle rechnet die Summe beider Spuren, wie sie liegen, mit gedrehter Polarit\u00e4t von B und nach dem Verschieben. Unter 150\u00a0Hz filtert ein Butterworth-Tiefpass 4. Ordnung beide Spuren gleich. Das schw\u00e4chste 100-ms-Fenster z\u00e4hlt nur Stellen, an denen beide Spuren spielen (je h\u00f6chstens 20\u00a0dB unter ihrem lautesten Fenster); bei Kick und Bass ist das der Moment, in dem der Tiefbass am st\u00e4rksten ausl\u00f6scht.\",\"erkl_polaritaet\":\"Gedrehte Polarit\u00e4t kehrt jeden Wert um und wirkt auf alle Frequenzen gleich. Ein Versatz dagegen dreht die Phase je Frequenz verschieden: Bei 1\u00a0ms liegt die erste Ausl\u00f6schung bei 500\u00a0Hz, die n\u00e4chste bei 1,5\u00a0kHz. Deshalb ersetzt eine gedrehte Polarit\u00e4t kein Verschieben. Schall legt bei 20 \u00b0C in Luft 344 m\\\/s zur\u00fcck, 1\u00a0ms entspricht also 34,4 cm Abstand zwischen zwei Mikrofonen.\",\"erkl_daw\":\"In FL Studio dreht der Fruity Stereo Shaper die Polarit\u00e4t eines oder beider Kan\u00e4le und verz\u00f6gert einen Kanal gegen den anderen; den Ausgleich einer Mixer-Spur nimmt FL Studio laut Handbuch auch von Hand in Millisekunden oder Samples an, Samples sind dabei die feinste Einstellung.\",\"erkl_messung\":\"Gepr\u00fcft an 21 Testf\u00e4llen mit bekanntem Versatz: Ganze und gebrochene Vers\u00e4tze trafen auf h\u00f6chstens 0,016 Werte, zwei Mikrofone mit Raumanteil und Rauschen (r = 0,32) auf 0,011 Werte, eine Snare oben und unten mit Hochpass am unteren Mikrofon als verschoben und verpolt. Ein Sinuston blieb mehrdeutig; Kick gegen Bass, Drums gegen Bass und unabh\u00e4ngiges Rauschen ergaben kein gemeinsames Signal. Nach dem vorgeschlagenen ffmpeg-Befehl lagen die Spuren in allen sieben nachgemessenen F\u00e4llen deckungsgleich, und die Summe traf die Vorhersage auf 0,1\u00a0dB. Im echten Browser (Chromium) ergab dieselbe Spur B als FLAC, MP3, AAC in M4A und Opus gegen die WAV-Fassung von A jeweils 64 Werte Versatz auf 0,002 Werte genau: Den Vorlauf der Encoder entfernt der Decoder, und Opus wird auf die Rate von A gebracht.\",\"h_artikel\":\"Artikel dazu\",\"art_sidechain_vor\":\"Wie Sidechain-Kompression den Bass bei jedem Kick absenkt, statt beide gegeneinander zu verschieben, zeigt die Anleitung \u201e\",\"art_sidechain_titel\":\"Sidechain-Kompression in FL Studio 2026\",\"art_sidechain_nach\":\"\u201c.\",\"art_versatz_vor\":\"Kammfilter, Snare oben und unten sowie Kick innen und au\u00dfen misst der Artikel \u201e\",\"art_versatz_titel\":\"Versatz und Polarit\u00e4t zweier Spuren\",\"art_versatz_nach\":\"\u201c.\",\"art_kickbass_vor\":\"Was Startphase, Stimmung, Hochpass und Ducking an der Summe von Kick und Bass im Tiefbass \u00e4ndern, misst der Artikel \u201e\",\"art_kickbass_titel\":\"Kick und Bass im Tiefbass\",\"art_kickbass_nach\":\"\u201c.\",\"art_stereo_vor\":\"Was eine Verz\u00f6gerung zwischen links und rechts in der Mono-Summe kostet, misst der Artikel \u201e\",\"art_stereo_titel\":\"Stereo-Verbreiterung\",\"art_stereo_nach\":\"\u201c.\",\"art_eq_vor\":\"Wie viel Latenz ein linearphasiger EQ mitbringt, eine h\u00e4ufige Ursache f\u00fcr Versatz in parallelen Wegen, misst der Artikel \u201e\",\"art_eq_titel\":\"Linearphasiger gegen minimalphasigen EQ\",\"art_eq_nach\":\"\u201c.\",\"quellen_titel\":\"Quellen\",\"grenze\":\"Gesucht wird nur bis \u00b1100\u00a0ms; ein gr\u00f6\u00dferer Versatz ergibt \u201ekein gemeinsames Signal\u201c. Ein Versatz, der \u00fcber die Datei wandert, etwa bei verschiedenen Taktgebern zweier Ger\u00e4te, hat keine feste Lage; gemessen wird dann ein Mittel \u00fcber die ersten 30\u00a0s. Filter verz\u00f6gern selbst: Ein Tiefpass bei 5\u00a0kHz auf Spur B verschob die gemessene Lage im Test um 3,9 Werte, und genau diese Laufzeit gleicht das Verschieben mit aus.\"};<\/p>\n<p>    \/\/ KERN-ANFANG ------------------------------------------------------------\n    \/\/ Versatz- und Polaritaetspruefer: Kreuzkorrelation zweier Spuren (oder links gegen rechts)\n    \/\/ in +-100 ms, dazu die Summe der beiden Spuren, gesamt und unter 150 Hz.\n    var MAX_VERSATZ_S = 0.1;       \/\/ gesuchter Bereich je Richtung\n    var ANALYSE_S = 30;            \/\/ hoechstens so viel Material geht in die Korrelation\n    var BLOCK = 65536, FFT_N = 131072;\n    var Q_KLAR = 5;                \/\/ geweisster Gipfel mindestens fuenfmal so hoch wie alles ausserhalb +-0,5 ms\n                                   \/\/ (Testdateien: gemeinsame Quelle 12 bis 74, Kick gegen Bass 2,2, Rauschen 1,0)\n    var R_MIN = 0.3;               \/\/ ohne klaren geweissten Gipfel: darunter kein gemeinsames Signal\n    var R_SCHWACH = 0.6;           \/\/ darunter nur teilweise gemeinsames Material\n    var R_POL = 0.2;               \/\/ darunter entscheidet die Wellenform die Polaritaet nicht\n    var MEHRDEUTIG = 0.9;          \/\/ ein zweiter Gipfel ab 90 % des ersten macht die Lage mehrdeutig\n    var TIEF_HZ = 150;\n    var FENSTER_S = 0.1, AKTIV_DB = 20;\n    var SCHALL_M_S = 344;          \/\/ 20 Grad Celsius, HyperPhysics<\/p>\n<p>    function db10(v) { return v > 0 ? 10 * Math.log10(v) : -Infinity; }<\/p>\n<p>    \/\/ Komplexe FFT, radix 2, an Ort und Stelle\n    function fft(re, im, invers) {\n        var n = re.length, i, j = 0, k, m, t;\n        for (i = 1; i < n; i++) {\n            k = n >> 1;\n            while (j & k) { j ^= k; k >>= 1; }\n            j |= k;\n            if (i < j) { t = re[i]; re[i] = re[j]; re[j] = t; t = im[i]; im[i] = im[j]; im[j] = t; }\n        }\n        for (m = 2; m <= n; m <<= 1) {\n            var w = (invers ? 2 : -2) * Math.PI \/ m, wr = Math.cos(w), wi = Math.sin(w), h = m >> 1;\n            for (i = 0; i < n; i += m) {\n                var cr = 1, ci = 0;\n                for (k = 0; k < h; k++) {\n                    var a = i + k, b = a + h, xr = re[b] * cr - im[b] * ci, xi = re[b] * ci + im[b] * cr;\n                    re[b] = re[a] - xr; im[b] = im[a] - xi; re[a] += xr; im[a] += xi;\n                    t = cr * wr - ci * wi; ci = cr * wi + ci * wr; cr = t;\n                }\n            }\n        }\n        if (invers) { for (i = 0; i < n; i++) { re[i] \/= n; im[i] \/= n; } }\n    }\n\n    function mono(kanaele) {\n        if (kanaele.length === 1) { return kanaele[0]; }\n        var n = kanaele[0].length, y = new Float32Array(n), c, i;\n        for (c = 0; c < kanaele.length; c++) { for (i = 0; i < n; i++) { y[i] += kanaele[c][i] \/ kanaele.length; } }\n        return y;\n    }\n\n    \/\/ Butterworth-Tiefpass 4. Ordnung als zwei Biquads (RBJ); gleiche Filter auf beiden Spuren\n    function tiefpass(x, fs, f0) {\n        var y = new Float32Array(x.length), i;\n        for (i = 0; i < x.length; i++) { y[i] = x[i]; }\n        [0.5411961, 1.3065630].forEach(function (q) {\n            var w = 2 * Math.PI * f0 \/ fs, c = Math.cos(w), al = Math.sin(w) \/ (2 * q), a0 = 1 + al;\n            var b0 = (1 - c) \/ 2 \/ a0, b1 = (1 - c) \/ a0, b2 = b0, a1 = -2 * c \/ a0, a2 = (1 - al) \/ a0;\n            var x1 = 0, x2 = 0, y1 = 0, y2 = 0;\n            for (i = 0; i < y.length; i++) {\n                var v = y[i], o = b0 * v + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;\n                x2 = x1; x1 = v; y2 = y1; y1 = o; y[i] = o;\n            }\n        });\n        return y;\n    }\n\n    \/\/ Kreuzspektrum ueber Bloecke summiert. Daraus zwei Funktionen ueber k in [-L, L]:\n    \/\/ r(k) = Summe a[n] b[n+k] \/ Wurzel(Ea * Eb(k)), die gewoehnliche normierte Korrelation, und\n    \/\/ w(k), dieselbe Korrelation mit geweisstem Spektrum (SCOT: Kreuzspektrum durch die Wurzel der\n    \/\/ beiden Leistungsspektren). w hat einen schmalen Gipfel auch dort, wo tiefe Toene und Nachhall\n    \/\/ r verschmieren. Positives k: b kommt k Werte spaeter als a; Index j = k + L.\n    function korrelation(a, b, fs) {\n        var L = Math.round(MAX_VERSATZ_S * fs), n = Math.min(a.length, b.length);\n        var anf = L, ende = Math.min(n - L, L + Math.round(ANALYSE_S * fs));\n        if (ende - anf < Math.round(0.05 * fs)) { return null; }\n        var re = new Float64Array(FFT_N), im = new Float64Array(FFT_N), re2 = new Float64Array(FFT_N), im2 = new Float64Array(FFT_N);\n        var gr = new Float64Array(FFT_N), gi = new Float64Array(FFT_N), paa = new Float64Array(FFT_N), pbb = new Float64Array(FFT_N), s, i, j;\n        for (s = anf; s < ende; s += BLOCK) {\n            var m = Math.min(BLOCK, ende - s);\n            re.fill(0); im.fill(0); re2.fill(0); im2.fill(0);\n            for (i = 0; i < m; i++) { re[i] = a[s + i]; }\n            for (i = 0; i < m + 2 * L; i++) { re2[i] = b[s - L + i]; }\n            fft(re, im, false); fft(re2, im2, false);\n            for (i = 0; i < FFT_N; i++) {       \/\/ konj(A) * B\n                gr[i] += re[i] * re2[i] + im[i] * im2[i]; gi[i] += re[i] * im2[i] - im[i] * re2[i];\n                paa[i] += re[i] * re[i] + im[i] * im[i]; pbb[i] += re2[i] * re2[i] + im2[i] * im2[i];\n            }\n        }\n        var nenner = new Float64Array(FFT_N), hoechst = 0;\n        for (i = 0; i < FFT_N; i++) { nenner[i] = Math.sqrt(paa[i] * pbb[i]); if (nenner[i] > hoechst) { hoechst = nenner[i]; } }\n        for (i = 0; i < FFT_N; i++) {\n            var d = nenner[i] + 1e-6 * hoechst;\n            re[i] = gr[i]; im[i] = gi[i]; re2[i] = gr[i] \/ d; im2[i] = gi[i] \/ d;\n        }\n        fft(re, im, true); fft(re2, im2, true);\n        var ea = 0, kum = new Float64Array(n + 1), r = new Float64Array(2 * L + 1), w = new Float64Array(2 * L + 1);\n        for (i = anf; i < ende; i++) { ea += a[i] * a[i]; }\n        for (i = 0; i < n; i++) { kum[i + 1] = kum[i] + b[i] * b[i]; }\n        for (j = 0; j <= 2 * L; j++) {\n            var eb = kum[ende - L + j] - kum[anf - L + j], nn = Math.sqrt(ea * eb);\n            r[j] = nn > 0 ? re[j] \/ nn : 0;\n            w[j] = re2[j];\n        }\n        return { r: r, w: w, L: L, anf: anf, ende: ende };\n    }<\/p>\n<p>    \/\/ Wert einer abgetasteten Funktion zwischen den Stuetzstellen (Lanczos-gefensterter Sinc, +-16)\n    function zwischen(f, t) {\n        var i0 = Math.floor(t), s = 0, j;\n        for (j = i0 - 15; j <= i0 + 16; j++) {\n            if (j < 0 || j >= f.length) { continue; }\n            var x = t - j;\n            s += f[j] * (x === 0 ? 1 : Math.sin(Math.PI * x) \/ (Math.PI * x) * Math.sin(Math.PI * x \/ 16) \/ (Math.PI * x \/ 16));\n        }\n        return s;\n    }\n    \/\/ Lage des Gipfels von |f| um die Stuetzstelle i, auf ein Tausendstel Wert genau\n    function fein(f, i) {\n        var best = i, bw = Math.abs(f[i]);\n        [0.05, 0.005, 0.0005].forEach(function (d) {\n            var mitte = best, t;\n            for (t = mitte - 20 * d; t <= mitte + 20 * d + d \/ 2; t += d) {\n                var v = Math.abs(zwischen(f, t));\n                if (v > bw) { bw = v; best = t; }\n            }\n        });\n        return best;\n    }\n    function hoechstesBei(f) {\n        var best = 0, i;\n        for (i = 1; i < f.length; i++) { if (Math.abs(f[i]) > Math.abs(f[best])) { best = i; } }\n        return best;\n    }<\/p>\n<p>    \/\/ Weitere Gipfel von |r| ab 90 % des Hauptgipfels, deren Tal zum Hauptgipfel unter die Haelfte faellt\n    function nebengipfel(r, best, L) {\n        var andere = [], i, k;\n        for (i = 1; i < r.length - 1; i++) {\n            var v = Math.abs(r[i]);\n            if (i === best || v < Math.abs(r[i - 1]) || v < Math.abs(r[i + 1]) || v < MEHRDEUTIG * Math.abs(r[best])) { continue; }\n            var tal = Infinity, a = Math.min(i, best), b = Math.max(i, best);\n            for (k = a; k <= b; k++) { tal = Math.min(tal, Math.abs(r[k])); }\n            if (tal < 0.5 * Math.abs(r[best])) { andere.push({ k: i - L, r: r[i] }); }\n        }\n        return andere.sort(function (x, y) { return Math.abs(y.r) - Math.abs(x.r); });\n    }\n\n    \/\/ Klarheit des geweissten Gipfels: Hoehe gegen den hoechsten Wert ausserhalb +-0,5 ms\n    function klarheit(w, j, fs) {\n        var rand = Math.max(3, Math.round(0.0005 * fs)), zweit = 0, i;\n        for (i = 0; i < w.length; i++) { if (Math.abs(i - j) > rand && Math.abs(w[i]) > zweit) { zweit = Math.abs(w[i]); } }\n        return zweit > 0 ? Math.abs(w[j]) \/ zweit : Infinity;\n    }<\/p>\n<p>    \/\/ Summe zweier Spuren gegen die Leistungssumme: +3 dB gleich und gleichphasig, 0 dB unabhaengig,\n    \/\/ -Unendlich gleich und gegenphasig. b wird um k verschoben (b[n+k] liegt unter a[n]) und mit v gewichtet.\n    function summe(a, b, k, v, anf, ende) {\n        var ea = 0, eb = 0, es = 0, i;\n        for (i = anf; i < ende; i++) {\n            var x = a[i], y = v * b[i + k];\n            ea += x * x; eb += y * y; es += (x + y) * (x + y);\n        }\n        return { gewinn: db10(es \/ (ea + eb)), ea: ea, eb: eb, r: ea > 0 && eb > 0 ? (es - ea - eb) \/ (2 * Math.sqrt(ea * eb)) : null };\n    }<\/p>\n<p>    \/\/ Schlechtestes 100-ms-Fenster, in dem beide Spuren spielen (je hoechstens 20 dB unter ihrem lautesten Fenster)\n    function fensterSumme(a, b, v, anf, ende, fs) {\n        var w = Math.round(FENSTER_S * fs), f = [], i, s, maxa = 0, maxb = 0;\n        for (s = anf; s + w <= ende; s += w) {\n            var ea = 0, eb = 0, es = 0;\n            for (i = s; i < s + w; i++) { var x = a[i], y = v * b[i]; ea += x * x; eb += y * y; es += (x + y) * (x + y); }\n            f.push({ s: s, ea: ea, eb: eb, es: es });\n            if (ea > maxa) { maxa = ea; }\n            if (eb > maxb) { maxb = eb; }\n        }\n        var grenze = Math.pow(10, -AKTIV_DB \/ 10), schlecht = null, n = 0;\n        f.forEach(function (x) {\n            if (x.ea < maxa * grenze || x.eb < maxb * grenze || x.ea === 0 || x.eb === 0) { return; }\n            n++;\n            var g = db10(x.es \/ (x.ea + x.eb));\n            if (schlecht === null || g < schlecht.gewinn) { schlecht = { gewinn: g, zeit_s: x.s \/ fs }; }\n        });\n        return { fenster: n, schlecht: schlecht };\n    }\n\n    function pruefen(kanaeleA, kanaeleB, fs) {\n        var a = mono(kanaeleA), b = mono(kanaeleB);\n        var kk = korrelation(a, b, fs);\n        if (!kk) { return null; }\n        var L = kk.L, anf = kk.anf, ende = kk.ende;\n        var jw = hoechstesBei(kk.w), q = klarheit(kk.w, jw, fs), jr = hoechstesBei(kk.r);\n        \/\/ ein Gipfel am Rand des Suchbereichs liegt vermutlich ausserhalb und zaehlt nicht als klar\n        var klar = q >= Q_KLAR && jw > 1 && jw < 2 * L - 1, j = klar ? jw : jr;\n        var t = fein(klar ? kk.w : kk.r, j), rw = zwischen(kk.r, t);\n        var andere = klar ? [] : nebengipfel(kk.r, jr, L);\n        var e = {\n            fs: fs, verfahren: klar ? 'geweisst' : 'direkt', klarheit: q,\n            versatz_werte: t - L, versatz_ms: 1000 * (t - L) \/ fs, r: rw, r_null: kk.r[L],\n            andere: andere.slice(0, 3).map(function (x) { return { ms: 1000 * x.k \/ fs, r: x.r }; }),\n            analysiert_s: (ende - anf) \/ fs, abstand_cm: Math.abs(t - L) \/ fs * SCHALL_M_S * 100\n        };\n        if (!klar &#038;&#038; Math.abs(kk.r[jr]) < R_MIN) { e.urteil = 'kein_bezug'; }\n        else if (andere.length) { e.urteil = 'mehrdeutig'; }\n        else {\n            var gedreht = rw <= -R_POL;\n            e.urteil = Math.abs(t - L) < 0.5 ? (gedreht ? 'verpolt' : 'deckend') : (gedreht ? 'versatz_verpolt' : 'versatz');\n        }\n        var fest = e.urteil === 'kein_bezug' || e.urteil === 'mehrdeutig';\n        e.schwach = !fest &#038;&#038; Math.abs(rw) < R_SCHWACH;\n        e.polaritaet = fest ? null : (Math.abs(rw) < R_POL ? 'unklar' : (rw < 0 ? 'gedreht' : 'gleich'));\n        var kb = fest ? 0 : Math.round(t - L);\n        if (!fest &#038;&#038; Math.abs(t - L) >= 0.5) { e.kerbe_hz = fs \/ (2 * Math.abs(t - L)); }\n        var sj = summe(a, b, 0, 1, anf, ende);\n        \/\/ nach dem Verschieben beide Polaritaeten, damit auch ein unklarer Fall eine Zahl hat\n        e.summe = { jetzt: sj.gewinn, gedreht: summe(a, b, 0, -1, anf, ende).gewinn, verschoben: fest ? null : summe(a, b, kb, 1, anf, ende).gewinn,\n            verschoben_gedreht: fest ? null : summe(a, b, kb, -1, anf, ende).gewinn };\n        \/\/ Tiefbass: beide Spuren gleich gefiltert, so wie sie jetzt liegen, und mit gedrehter Polaritaet von B\n        var at = tiefpass(a, fs, TIEF_HZ), bt = tiefpass(b, fs, TIEF_HZ);\n        var tj = summe(at, bt, 0, 1, anf, ende), tg = summe(at, bt, 0, -1, anf, ende);\n        e.tief = {\n            jetzt: tj.gewinn, gedreht: tg.gewinn, r: tj.r,\n            anteil_a: db10(tj.ea \/ sj.ea), anteil_b: db10(tj.eb \/ sj.eb),\n            fenster_jetzt: fensterSumme(at, bt, 1, anf, ende, fs), fenster_gedreht: fensterSumme(at, bt, -1, anf, ende, fs)\n        };\n        e.korrektur = fest ? null : { werte: kb, polaritaet: e.polaritaet === 'gedreht' };\n        return e;\n    }<\/p>\n<p>    \/\/ ffmpeg-Befehl fuer Spur B: frueher legen (atrim), spaeter legen (adelay) und\/oder Polaritaet drehen\n    function befehl(e) {\n        if (!e || !e.korrektur) { return ''; }\n        var f = [], k = e.korrektur.werte;\n        if (k > 0) { f.push('atrim=start_sample=' + k, 'asetpts=PTS-STARTPTS'); }\n        if (k < 0) { f.push('adelay=delays=' + (-k) + 'S:all=1'); }\n        if (e.korrektur.polaritaet) { f.push('aeval=-val(ch):c=same'); }\n        return f.length ? 'ffmpeg -i b.wav -af \"' + f.join(',') + '\" b_korrigiert.wav' : '';\n    }\n\n    \/\/ Zwei Dateien oder eine Stereodatei (links gegen rechts)\n    function spurenPruefen(infoA, infoB) {\n        if (!infoB) {\n            if (infoA.kanaele.length < 2) { return { fehler: 'mono' }; }\n            return { modus: 'lr', e: pruefen([infoA.kanaele[0]], [infoA.kanaele[1]], infoA.rate) };\n        }\n        if (infoA.rate !== infoB.rate) { return { fehler: 'rate' }; }\n        return { modus: 'ab', e: pruefen(infoA.kanaele, infoB.kanaele, infoA.rate) };\n    }\n    function str(u8, o, l) { var s = ''; for (var i = 0; i < l &#038;&#038; o + i < u8.length; i++) { s += String.fromCharCode(u8[o + i]); } return s; }\n    function le16(u8, o) { return u8[o] | (u8[o + 1] << 8); }\n    function le32(u8, o) { return (u8[o] | (u8[o + 1] << 8) | (u8[o + 2] << 16)) + ((u8[o + 3] << 24) >>> 0); }\n    function be16(u8, o) { return (u8[o] << 8) | u8[o + 1]; }\n    function be32(u8, o) { return ((u8[o] << 24) >>> 0) + (u8[o + 1] << 16) + (u8[o + 2] << 8) + u8[o + 3]; }\n\n    function pcm(puffer, start, laenge, anzahl, bytes, gleit, klein) {\n        var rahmen = Math.floor(laenge \/ (bytes * anzahl)), raus = [], c, i;\n        for (c = 0; c < anzahl; c++) { raus.push(new Float32Array(rahmen)); }\n        var dv = new DataView(puffer, start, rahmen * bytes * anzahl), u8 = new Uint8Array(puffer, start, rahmen * bytes * anzahl);\n        var teiler = Math.pow(2, bytes * 8 - 1), o = 0, v;\n        for (i = 0; i < rahmen; i++) {\n            for (c = 0; c < anzahl; c++) {\n                if (gleit) { v = bytes === 4 ? dv.getFloat32(o, klein) : dv.getFloat64(o, klein); }\n                else if (bytes === 1) { v = (klein ? u8[o] - 128 : dv.getInt8(o)) \/ teiler; }\n                else if (bytes === 2) { v = dv.getInt16(o, klein) \/ teiler; }\n                else if (bytes === 3) {\n                    var w = klein ? (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 \/ teiler;\n                } else { v = dv.getInt32(o, klein) \/ teiler; }\n                raus[c][i] = v;\n                o += bytes;\n            }\n        }\n        return raus;\n    }\n\n    function wavLesen(puffer) {\n        var u8 = new Uint8Array(puffer), p = 12, fmt = null, ds64 = null;\n        while (p + 8 <= u8.length) {\n            var id = str(u8, p, 4), l = le32(u8, p + 4);\n            if (id === 'ds64' &#038;&#038; l >= 16) { ds64 = le32(u8, p + 16) + le32(u8, p + 20) * 4294967296; }\n            if (id === 'fmt ') {\n                var tag = le16(u8, p + 8);\n                if (tag === 0xFFFE && l >= 26) { tag = le16(u8, p + 32); }\n                fmt = { tag: tag, anzahl: le16(u8, p + 10), rate: le32(u8, p + 12), bits: le16(u8, p + 22) };\n            } else if (id === 'data') {\n                if (l === 0xFFFFFFFF && ds64 !== null) { l = ds64; }\n                if (!fmt || (fmt.tag !== 1 && fmt.tag !== 3)) { return null; }\n                var bytes = fmt.bits \/ 8;\n                if ([1, 2, 3, 4, 8].indexOf(bytes) === -1 || !fmt.anzahl) { return null; }\n                return { format: 'WAV', rate: fmt.rate, kanaele: pcm(puffer, p + 8, Math.min(l, u8.length - p - 8), fmt.anzahl, bytes, fmt.tag === 3, true) };\n            }\n            if (l === 0xFFFFFFFF) { break; }\n            p += 8 + l + (l & 1);\n        }\n        return null;\n    }<\/p>\n<p>    function aiffLesen(puffer, aifc) {\n        var u8 = new Uint8Array(puffer), p = 12, comm = null;\n        while (p + 8 <= u8.length) {\n            var id = str(u8, p, 4), l = be32(u8, p + 4);\n            if (id === 'COMM') {\n                var exp = be16(u8, p + 16) &#038; 0x7FFF, hi = be32(u8, p + 18), lo = be32(u8, p + 22);\n                comm = { anzahl: be16(u8, p + 8), bits: be16(u8, p + 14), rate: Math.round((hi * 4294967296 + lo) * Math.pow(2, exp - 16383 - 63)),\n                         art: aifc &#038;&#038; l >= 22 ? str(u8, p + 26, 4) : 'NONE' };\n            } else if (id === 'SSND' && comm) {\n                var versatz = be32(u8, p + 8), start = p + 16 + versatz, laenge = Math.min(l - 8 - versatz, u8.length - start);\n                var gleit = \/^(fl32|FL32|fl64|FL64)$\/.test(comm.art);\n                if (!gleit && ['NONE', 'twos', 'sowt'].indexOf(comm.art) === -1) { return null; }\n                var bytes = gleit ? (comm.art.slice(2) === '32' ? 4 : 8) : Math.ceil(comm.bits \/ 8);\n                return { format: 'AIFF', rate: comm.rate, kanaele: pcm(puffer, start, laenge, comm.anzahl, bytes, gleit, comm.art === 'sowt') };\n            }\n            p += 8 + l + (l & 1);\n        }\n        return null;\n    }<\/p>\n<p>    \/\/ Abtastrate komprimierter Formate aus dem Kopf, damit der Decoder nicht umrechnet.\n    \/\/ Rate aus dem ersten Eintrag der Box stsd (AudioSampleEntry, 16.16 bei +32 ab Eintrag). Der Kopf kann am\n    \/\/ Dateiende stehen, deshalb wird die ganze Datei durchsucht. Raten ueber 65535 Hz passen nicht in das Feld.\n    function mp4Rate(puffer) {\n        var u = new Uint8Array(puffer), i;\n        for (i = 4; i + 46 < u.length; i++) {\n            if (u[i] === 0x73 &#038;&#038; u[i + 1] === 0x74 &#038;&#038; u[i + 2] === 0x73 &#038;&#038; u[i + 3] === 0x64) {\n                var r = (u[i + 44] << 8) | u[i + 45];\n                return r >= 3000 ? r : null;\n            }\n        }\n        return null;\n    }<\/p>\n<p>    function kopfRate(puffer) {\n        var u8 = new Uint8Array(puffer, 0, Math.min(puffer.byteLength, 1 << 20)), k = str(u8, 0, 4), p = 0;\n        if (k === 'ID3' &#038;&#038; u8.length > 10) {\n            p = 10 + ((u8[6] & 0x7f) << 21 | (u8[7] &#038; 0x7f) << 14 | (u8[8] &#038; 0x7f) << 7 | (u8[9] &#038; 0x7f));\n            if (str(u8, p, 4) === 'fLaC') { k = 'fLaC'; }\n        }\n        if (k === 'fLaC') { var s = p + 8; return { format: 'FLAC', rate: (u8[s + 10] << 12) | (u8[s + 11] << 4) | (u8[s + 12] >> 4) }; }\n        if (k === 'OggS' && u8.length > 64) {\n            var d = 27 + u8[26];\n            if (str(u8, d + 1, 6) === 'vorbis') { return { format: 'Ogg Vorbis', rate: le32(u8, d + 12) }; }\n            if (str(u8, d, 8) === 'OpusHead') { return { format: 'Opus', rate: 48000 }; }\n            return { format: 'Ogg', rate: null };\n        }\n        if (str(u8, 4, 4) === 'ftyp') { return { format: 'MP4', rate: mp4Rate(puffer) }; }\n        for (var j = p; j < Math.min(u8.length - 4, p + 65536); j++) {\n            if (u8[j] !== 0xFF || (u8[j + 1] &#038; 0xE0) !== 0xE0) { continue; }\n            var version = (u8[j + 1] >> 3) & 3, schicht = (u8[j + 1] >> 1) & 3, ri = (u8[j + 2] >> 2) & 3, bri = u8[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: 'MP3', rate: version === 3 ? basis : (version === 2 ? basis \/ 2 : basis \/ 4) };\n        }\n        return { format: null, rate: null };\n    }<\/p>\n<p>    \/\/ WAV und AIFF selbst lesen; null heisst: den Decoder des Browsers fragen.\n    function direktLesen(puffer) {\n        var u8 = new Uint8Array(puffer);\n        if (u8.length < 16) { return null; }\n        var k = str(u8, 0, 4), a = str(u8, 8, 4);\n        if ((k === 'RIFF' || k === 'RF64' || k === 'BW64') &#038;&#038; a === 'WAVE') { return wavLesen(puffer); }\n        if (k === 'FORM' &#038;&#038; (a === 'AIFF' || a === 'AIFC')) { return aiffLesen(puffer, a === 'AIFC'); }\n        return null;\n    }\n\n    \/\/ KERN-ENDE --------------------------------------------------------------\n\n\n    function el(id) { return document.getElementById(id); }\n    var NB = ' ';\n    function satz(k, w) { return (T[k] || '').replace(\/\\{(\\w+)\\}\/g, function (_, x) { return w &#038;&#038; w[x] !== undefined ? w[x] : ''; }); }\n    function zahl(v, st) {\n        if (v === -Infinity || (typeof v === 'number' &#038;&#038; v < -99)) { return '\u2212\u221e'; }\n        if (v === null || v === undefined || !isFinite(v)) { return '\u2013'; }\n        var s = Number(v).toFixed(st === undefined ? 1 : st);\n        if (\/^-0(\\.0+)?$\/.test(s)) { s = s.slice(1); }\n        s = s.replace('-', '\u2212');\n        return T.dezimal === ',' ? s.replace('.', ',') : s;\n    }\n    function vorz(v, st) {\n        var s = zahl(v, st);\n        return typeof v === 'number' &#038;&#038; isFinite(v) &#038;&#038; Number(Number(v).toFixed(st === undefined ? 1 : st)) > 0 ? '+' + s : s;\n    }\n    function db(v) { return v === null || v === undefined ? '\u2013' : vorz(v, 1) + NB + 'dB'; }\n    function zeit(s) { var m = Math.floor(s \/ 60), r = s - 60 * m; return m + ':' + (r < 10 ? '0' : '') + zahl(r, 1); }\n    function hz(f) { return f >= 1000 ? zahl(f \/ 1000, f >= 10000 ? 1 : 2) + NB + 'kHz' : zahl(f, 0) + NB + 'Hz'; }<\/p>\n<p>    function kopfUndText(erg) {\n        var e = erg.e, ms = zahl(Math.abs(e.versatz_ms), 3) + NB + 'ms';\n        var werte = zahl(Math.abs(e.korrektur ? e.korrektur.werte : 0), 0);\n        var w = { ms: ms, lage: satz(e.versatz_werte > 0 ? 'spaeter' : 'frueher', { ms: ms }), werte: werte, r: zahl(e.r, 2) };\n        var kopf = satz('urteil_' + e.urteil, w), texte = [satz('urteil_text_' + e.urteil, w)];\n        if (e.urteil === 'mehrdeutig') {\n            texte.push(satz('kandidaten', { liste: [{ ms: e.versatz_ms, r: e.r }].concat(e.andere).map(function (x) {\n                return zahl(x.ms, 2) + NB + 'ms (r' + NB + '=' + NB + zahl(x.r, 2) + ')'; }).join(', ') }));\n        }\n        if (e.schwach) { texte.push(satz('hinweis_schwach', w)); }\n        if (e.polaritaet === 'unklar') { texte.push(satz('hinweis_unklar', w)); }\n        if (e.kerbe_hz) { texte.push(satz('hinweis_kerbe', { hz: hz(e.kerbe_hz), ms: ms, cm: zahl(e.abstand_cm, 1) + NB + 'cm' })); }\n        if (erg.modus === 'lr') { texte.push(T.hinweis_lr); }\n        if (erg.dekodiert) { texte.push(satz('hinweis_dekodiert', { hz: zahl(e.fs, 0) + NB + 'Hz' })); }\n        return { kopf: kopf, texte: texte, stufe: (e.urteil === 'deckend' || e.urteil === 'kein_bezug' || e.urteil === 'mehrdeutig') ? 'gut' : 'tun' };\n    }<\/p>\n<p>    function summenZeilen(e) {\n        var kaum = e.tief.anteil_a < -30 || e.tief.anteil_b < -30;\n        function fenster(f) { return kaum ? T.kaum_tief : (f.schlecht ? db(f.schlecht.gewinn) + ' (' + zeit(f.schlecht.zeit_s) + ')' : '\u2013'); }\n        var z = [\n            [T.fall_jetzt, db(e.summe.jetzt), kaum ? T.kaum_tief : db(e.tief.jetzt), fenster(e.tief.fenster_jetzt)],\n            [T.fall_gedreht, db(e.summe.gedreht), kaum ? T.kaum_tief : db(e.tief.gedreht), fenster(e.tief.fenster_gedreht)]\n        ];\n        if (e.korrektur &#038;&#038; e.korrektur.werte !== 0) {\n            z.push([satz('fall_verschoben', { werte: zahl(e.korrektur.werte, 0) }), db(e.summe.verschoben), '\u2013', '\u2013']);\n            z.push([satz('fall_verschoben_gedreht', { werte: zahl(e.korrektur.werte, 0) }), db(e.summe.verschoben_gedreht), '\u2013', '\u2013']);\n        }\n        return z;\n    }\n\n    function bericht(x) {\n        var e = x.erg.e, ku = kopfUndText(x.erg), z = [T.bericht_kopf + ': ' + x.namen.join(' \/ ')];\n        z.push(ku.kopf);\n        z.push(T.k_versatz + ': ' + zahl(e.versatz_ms, 3) + ' ms (' + zahl(e.versatz_werte, 2) + ' ' + T.werte + ')');\n        z.push(T.k_polaritaet + ': ' + (e.polaritaet ? T['pol_' + e.polaritaet] : '\u2013') + '; r = ' + zahl(e.r, 2));\n        summenZeilen(e).forEach(function (s) { z.push(s.join(' | ')); });\n        var b = befehl(e);\n        if (b) { z.push(b); }\n        return z.join('\\n');\n    }\n\n    function kachel(name, wert) {\n        var d = document.createElement('div'); d.className = 'vp-kachel';\n        var a = document.createElement('div'); a.className = 'vp-kachel-name'; a.textContent = name;\n        var b = document.createElement('div'); b.className = 'vp-kachel-wert'; b.textContent = wert;\n        d.appendChild(a); d.appendChild(b);\n        return d;\n    }\n\n    function darstellen(x) {\n        var e = x.erg.e;\n        if (!el('vp-kacheln')) { return x; }\n        var fest = e.urteil === 'kein_bezug' || e.urteil === 'mehrdeutig', k = el('vp-kacheln');\n        k.textContent = '';\n        k.appendChild(kachel(T.k_versatz, fest ? '\u2013' : vorz(e.versatz_ms, 3) + NB + 'ms'));\n        k.appendChild(kachel(T.k_werte, fest ? '\u2013' : vorz(e.versatz_werte, 2)));\n        k.appendChild(kachel(T.k_polaritaet, e.polaritaet ? T['pol_' + e.polaritaet] : '\u2013'));\n        k.appendChild(kachel(T.k_r, zahl(e.r, 2)));\n        var ku = kopfUndText(x.erg), u = el('vp-urteil');\n        u.className = 'vp-urteil vp-u-' + ku.stufe;\n        u.textContent = '';\n        var kopf = document.createElement('div'); kopf.className = 'vp-urteil-kopf'; kopf.textContent = ku.kopf;\n        u.appendChild(kopf);\n        ku.texte.forEach(function (t) { var p = document.createElement('p'); p.className = 'vp-klein'; p.textContent = t; u.appendChild(p); });\n        var b = befehl(e);\n        if (b) {\n            var bb = document.createElement('div'); bb.className = 'vp-befehl'; bb.id = 'vp-befehl'; bb.textContent = b;\n            var bh = document.createElement('p'); bh.className = 'vp-klein'; bh.textContent = T.befehl_hinweis;\n            u.appendChild(bb); u.appendChild(bh);\n        }\n        var t = el('vp-summen'), namen = [T.sp_fall, T.sp_gesamt, T.sp_tief, T.sp_fenster];\n        t.textContent = '';\n        summenZeilen(e).forEach(function (zeile) {\n            var tr = document.createElement('tr');\n            zeile.forEach(function (w, i) {\n                var td = document.createElement('td');\n                if (i > 0) { td.className = 'vp-wert'; td.setAttribute('data-name', namen[i]); }\n                td.textContent = w; tr.appendChild(td);\n            });\n            t.appendChild(tr);\n        });\n        el('vp-summe-hinweis').textContent = satz('summe_hinweis', { s: zahl(e.analysiert_s, 1) + NB + 's' });\n        el('vp-ausgabe').hidden = false;\n        el('vp-fehler').hidden = true;\n        return x;\n    }<\/p>\n<p>    function fehlerZeigen(s) {\n        var f = el('vp-fehler');\n        if (!f) { return; }\n        f.textContent = s; f.hidden = false;\n        el('vp-ausgabe').hidden = true;\n        el('vp-status').textContent = '';\n    }<\/p>\n<p>    function dekodieren(puffer, rate) {\n        return new Promise(function (ok, schlecht) {\n            var Ctx = window.OfflineAudioContext || window.webkitOfflineAudioContext;\n            if (!Ctx) { schlecht(new Error('webaudio')); return; }\n            var ctx, fertig = false;\n            try { ctx = new Ctx(1, 1, rate); } catch (x) { ctx = new Ctx(1, 1, 48000); }\n            function gut(b) { if (!fertig) { fertig = true; ok(b); } }\n            function nein(x) { if (!fertig) { fertig = true; schlecht(x || new Error('dekodieren')); } }\n            setTimeout(function () { nein(new Error('zeit')); }, 60000);\n            try { var p = ctx.decodeAudioData(puffer, gut, nein); if (p && p.then) { p.then(gut, nein); } } catch (x) { nein(x); }\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>    \/\/ Eine Datei vorab: WAV und AIFF direkt gelesen, alles andere mit Format und Rate aus dem Kopf fuer den Decoder\n    function vorlesen(puffer) {\n        var info = null;\n        try { info = direktLesen(puffer); } catch (x) { info = null; }\n        if (info) { return { info: info }; }\n        var kopf = kopfRate(puffer);\n        return kopf.format ? { kopf: kopf, puffer: puffer } : { fehler: 'format' };\n    }\n    \/\/ Der Decoder des Browsers rechnet auf die Rate seines Kontexts um. Deshalb wird eine dekodierte Spur gleich\n    \/\/ in der Rate der anderen Spur dekodiert; ohne direkt gelesene Spur in der Rate aus dem Kopf von A.\n    function fertiglesen(v, ziel) {\n        if (v.info) { return Promise.resolve(v.info); }\n        return dekodieren(v.puffer.slice(0), ziel).then(function (b) {\n            var k = [];\n            for (var c = 0; c < b.numberOfChannels; c++) { k.push(b.getChannelData(c)); }\n            return { format: v.kopf.format, rate: b.sampleRate, kanaele: k, dekodiert: true };\n        }, function () { return Promise.reject('lesen'); });\n    }\n    function passend(r) { return r &#038;&#038; r >= 3000 && r <= 768000 ? r : null; }\n\n    var letztes = null;\n    \/\/ pufferA, pufferB (oder null fuer links gegen rechts), Namen fuer den Bericht\n    function verarbeiten(pufferA, pufferB, namen) {\n        if (el('vp-status')) { el('vp-status').textContent = T.status_lesen; }\n        var va = vorlesen(pufferA), vb = pufferB ? vorlesen(pufferB) : null;\n        if (va.fehler || (vb &#038;&#038; vb.fehler)) { fehlerZeigen(T.fehler_format); return Promise.resolve(null); }\n        var ziel = va.info ? va.info.rate : (vb &#038;&#038; vb.info ? vb.info.rate : (passend(va.kopf.rate) || (vb &#038;&#038; passend(vb.kopf.rate)) || 48000));\n        return Promise.all([fertiglesen(va, ziel), vb ? fertiglesen(vb, ziel) : Promise.resolve(null)]).then(function (i) {\n            var a = i[0], b = i[1], n = Math.min(a.kanaele[0].length, b ? b.kanaele[0].length : Infinity);\n            if (b &#038;&#038; a.rate !== b.rate) { fehlerZeigen(satz('fehler_rate', { a: a.rate, b: b.rate })); return null; }\n            if (!b &#038;&#038; a.kanaele.length < 2) { fehlerZeigen(T.fehler_mono); return null; }\n            if (n < a.rate * 0.25) { fehlerZeigen(T.fehler_kurz); return null; }\n            if (el('vp-status')) { el('vp-status').textContent = T.status_messen; }\n            return new Promise(function (ok) {\n                spaeter(function () {\n                    var erg = spurenPruefen(a, b);\n                    if (el('vp-status')) { el('vp-status').textContent = ''; }\n                    if (!erg || erg.fehler || !erg.e) { fehlerZeigen(T.fehler_kurz); ok(null); return; }\n                    erg.dekodiert = [a, b].some(function (x) { return x &#038;&#038; x.dekodiert; });\n                    letztes = { erg: erg, namen: namen || [] };\n                    ok(darstellen(letztes));\n                });\n            });\n        }, function (grund) { fehlerZeigen(grund === 'format' ? T.fehler_format : T.fehler_lesen); return null; });\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.VP = { T: T, spurenPruefen: spurenPruefen, direktLesen: direktLesen, befehl: befehl, verarbeiten: verarbeiten,\n        bericht: bericht, summenZeilen: summenZeilen, letztes: function () { return letztes; } };\n\n    var gewaehlt = { a: null, b: null }, messen = el('vp-messen');\n    if (!messen) { return; }\n    function nehmen(seite, datei) {\n        if (!datei) { return; }\n        var leser = new FileReader();\n        leser.onload = function () {\n            gewaehlt[seite] = { puffer: leser.result, name: datei.name };\n            el('vp-name-' + seite).textContent = datei.name;\n            messen.disabled = !gewaehlt.a;\n        };\n        leser.onerror = function () { fehlerZeigen(T.fehler_lesen); };\n        try { leser.readAsArrayBuffer(datei); } catch (x) { fehlerZeigen(T.fehler_lesen); }\n    }\n    ['a', 'b'].forEach(function (seite) {\n        var zone = el('vp-zone-' + seite), eingabe = el('vp-datei-' + seite);\n        el('vp-knopf-' + seite).addEventListener('click', function () { eingabe.click(); });\n        eingabe.addEventListener('change', function () { nehmen(seite, eingabe.files &#038;&#038; eingabe.files[0]); eingabe.value = ''; });\n        ['dragenter', 'dragover'].forEach(function (t) { zone.addEventListener(t, function (ev) { ev.preventDefault(); zone.classList.add('vp-ueber'); }); });\n        ['dragleave', 'drop'].forEach(function (t) { zone.addEventListener(t, function (ev) { ev.preventDefault(); zone.classList.remove('vp-ueber'); }); });\n        zone.addEventListener('drop', function (ev) { ev.preventDefault(); nehmen(seite, ev.dataTransfer &#038;&#038; ev.dataTransfer.files &#038;&#038; ev.dataTransfer.files[0]); });\n    });\n    messen.addEventListener('click', function () {\n        if (!gewaehlt.a) { return; }\n        verarbeiten(gewaehlt.a.puffer, gewaehlt.b ? gewaehlt.b.puffer : null, [gewaehlt.a.name].concat(gewaehlt.b ? [gewaehlt.b.name] : []));\n    });\n    el('vp-leeren').addEventListener('click', function () {\n        gewaehlt = { a: null, b: null };\n        el('vp-name-a').textContent = ''; el('vp-name-b').textContent = '';\n        messen.disabled = true;\n        el('vp-ausgabe').hidden = true; el('vp-fehler').hidden = true; el('vp-status').textContent = '';\n    });\n    var kop = el('vp-kopieren'), kopiert = el('vp-kopiert');\n    kop.addEventListener('click', function () {\n        if (!letztes) { return; }\n        var t = bericht(letztes);\n        if (navigator.clipboard &#038;&#038; navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(t).then(function () { kopiert.textContent = T.kopiert; }, function () { kopiert.textContent = T.kopieren_fehler; });\n        } else { kopiert.textContent = T.kopieren_fehler; }\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Misst den Versatz zwischen zwei Spuren oder zwischen links und rechts auf Bruchteile eines Werts, erkennt gedrehte Polarit\u00e4t und rechnet, was die Summe gesamt und unter 150\u00a0Hz gewinnt oder verliert. Liefert den ffmpeg-Befehl, der die zweite Spur verschiebt und dreht.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9283,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92903],"class_list":["post-20241","page","type-page","status-publish","hentry","tag-music-production-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - 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\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Misst den Versatz zwischen zwei Spuren oder zwischen links und rechts auf Bruchteile eines Werts, erkennt gedrehte Polarit\u00e4t und rechnet, was die Summe gesamt und unter 150\u00a0Hz gewinnt oder verliert. Liefert den ffmpeg-Befehl, der die zweite Spur verschiebt und dreht.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-23T19:59:45+00:00\" \/>\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=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/time-offset-polarity-checker-two-tracks\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/time-offset-polarity-checker-two-tracks\\\/\",\"name\":\"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-23T19:37:58+00:00\",\"dateModified\":\"2026-09-23T19:59:45+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/time-offset-polarity-checker-two-tracks\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/time-offset-polarity-checker-two-tracks\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/time-offset-polarity-checker-two-tracks\\\/#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\\\/toolbox-2\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren\"}]},{\"@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":"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - 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\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/","og_locale":"en_US","og_type":"article","og_title":"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - Lukas Wojcik - Blog","og_description":"Misst den Versatz zwischen zwei Spuren oder zwischen links und rechts auf Bruchteile eines Werts, erkennt gedrehte Polarit\u00e4t und rechnet, was die Summe gesamt und unter 150\u00a0Hz gewinnt oder verliert. Liefert den ffmpeg-Befehl, der die zweite Spur verschiebt und dreht.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-09-23T19:59:45+00:00","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":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/","url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/","name":"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-23T19:37:58+00:00","dateModified":"2026-09-23T19:59:45+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/time-offset-polarity-checker-two-tracks\/#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\/toolbox-2\/"},{"@type":"ListItem","position":3,"name":"Versatz- und Polarit\u00e4tspr\u00fcfer: zeitlicher Versatz und gedrehte Polarit\u00e4t zweier Spuren"}]},{"@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\/20241","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=20241"}],"version-history":[{"count":3,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20241\/revisions"}],"predecessor-version":[{"id":20308,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20241\/revisions\/20308"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9283"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=20241"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}