{"id":20242,"date":"2026-09-23T21:38:02","date_gmt":"2026-09-23T19:38:02","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/time-offset-polarity-checker-two-tracks\/"},"modified":"2026-09-23T21:59:49","modified_gmt":"2026-09-23T19:59:49","slug":"time-offset-polarity-checker-two-tracks","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/","title":{"rendered":"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek"},"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;\">Mierzy, o ile druga \u015bcie\u017cka jest przesuni\u0119ta wzgl\u0119dem pierwszej i czy ma odwr\u00f3con\u0105 polaryzacj\u0119: dwa mikrofony przy jednym \u017ar\u00f3dle, DI i wzmacniacz basu, \u015bcie\u017cka przed wtyczk\u0105 z op\u00f3\u017anieniem i po niej. Pokazuje te\u017c, co suma obu \u015bcie\u017cek zyskuje lub traci w ca\u0142ym pa\u015bmie i poni\u017cej 150\u00a0Hz, tak\u017ce dla stopy i basu, kt\u00f3re nie maj\u0105 wsp\u00f3lnego \u017ar\u00f3d\u0142a. Pliki s\u0105 odczytywane w przegl\u0105darce i nie trafiaj\u0105 na serwer.<\/p>\n<div class=\"vp-zonen\">\n<div id=\"vp-zone-a\" class=\"vp-zone\">\n<p class=\"vp-zone-name\">\u015acie\u017cka A (odniesienie)<\/p>\n<p>            <button id=\"vp-knopf-a\" type=\"button\" class=\"vp-waehlen\">Wyb\u00f3r pliku<\/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\">\u015acie\u017cka B (do przesuni\u0119cia)<\/p>\n<p>            <button id=\"vp-knopf-b\" type=\"button\" class=\"vp-waehlen\">Wyb\u00f3r pliku<\/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;\">Przy samej \u015bcie\u017cce A w postaci pliku stereo pomiar obejmuje lewy kana\u0142 wzgl\u0119dem prawego. WAV i AIFF s\u0105 odczytywane pr\u00f3bka po pr\u00f3bce; FLAC, MP3, M4A, Ogg i Opus przechodz\u0105 przez dekoder przegl\u0105darki.<\/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;\">Pomiar<\/button><br \/>\n    <button id=\"vp-leeren\" type=\"button\" class=\"vp-knopf\" style=\"margin-left: 8px;\">Czyszczenie wyboru<\/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\">Suma obu \u015bcie\u017cek<\/div>\n<div class=\"vp-tabelle\">\n<table class=\"vp-karten\">\n<thead>\n<tr>\n<th>Przypadek<\/th>\n<th>Suma w ca\u0142ym pa\u015bmie<\/th>\n<th>Poni\u017cej 150\u00a0Hz<\/th>\n<th>Najs\u0142absze okno 100\u00a0ms poni\u017cej 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\">Kopiowanie wyniku<\/button><br \/>\n        <span id=\"vp-kopiert\" class=\"vp-klein\" style=\"margin-left: 10px;\"><\/span>\n    <\/div>\n<div class=\"vp-h\">Jak przebiega pomiar<\/div>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Z maksymalnie 30\u00a0s wsp\u00f3lnego materia\u0142u, od 0,1\u00a0s po pocz\u0105tku, obliczana jest korelacja wzajemna obu \u015bcie\u017cek dla przesuni\u0119\u0107 do \u00b1100\u00a0ms. Po\u0142o\u017cenie szczytu pochodzi z wersji wybielonej (SCOT), w kt\u00f3rej ka\u017cda cz\u0119stotliwo\u015b\u0107 liczy si\u0119 tak samo; dzi\u0119ki temu niskie tony i pog\u0142os nie rozmywaj\u0105 szczytu. Warto\u015bci mi\u0119dzy pr\u00f3bkami daje interpolacja sinc z dok\u0142adno\u015bci\u0105 do jednej tysi\u0119cznej pr\u00f3bki. Zgodno\u015b\u0107 i polaryzacja pochodz\u0105 ze zwyk\u0142ej znormalizowanej korelacji w tym miejscu; wa\u017cy ona wed\u0142ug energii, tak jak s\u0142ycha\u0107 sum\u0119.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Tabela liczy sum\u0119 obu \u015bcie\u017cek w obecnym po\u0142o\u017ceniu, z odwr\u00f3con\u0105 polaryzacj\u0105 B i po przesuni\u0119ciu. Poni\u017cej 150\u00a0Hz obie \u015bcie\u017cki przechodz\u0105 przez ten sam filtr dolnoprzepustowy Butterwortha 4. rz\u0119du. Najs\u0142absze okno 100\u00a0ms obejmuje tylko miejsca, w kt\u00f3rych graj\u0105 obie \u015bcie\u017cki (ka\u017cda najwy\u017cej 20\u00a0dB poni\u017cej najg\u0142o\u015bniejszego okna tej \u015bcie\u017cki); przy stopie i basie to moment, w kt\u00f3rym najni\u017cszy zakres wygasza si\u0119 najsilniej.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Odwr\u00f3cenie polaryzacji zmienia znak ka\u017cdej pr\u00f3bki i dzia\u0142a na wszystkie cz\u0119stotliwo\u015bci jednakowo. Przesuni\u0119cie natomiast obraca faz\u0119 r\u00f3\u017cnie dla ka\u017cdej cz\u0119stotliwo\u015bci: przy 1\u00a0ms pierwsze wygaszenie wypada przy 500\u00a0Hz, nast\u0119pne przy 1,5\u00a0kHz. Dlatego odwr\u00f3cona polaryzacja nie zast\u0119puje przesuni\u0119cia. D\u017awi\u0119k w powietrzu przy 20 \u00b0C pokonuje 344 m\/s, wi\u0119c 1\u00a0ms odpowiada 34,4 cm odleg\u0142o\u015bci mi\u0119dzy dwoma mikrofonami.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">W FL Studio Fruity Stereo Shaper odwraca polaryzacj\u0119 jednego lub obu kana\u0142\u00f3w i op\u00f3\u017ania jeden kana\u0142 wzgl\u0119dem drugiego; wed\u0142ug podr\u0119cznika kompensacj\u0119 op\u00f3\u017anienia \u015bcie\u017cki miksera FL Studio przyjmuje tak\u017ce r\u0119cznie w milisekundach lub pr\u00f3bkach, przy czym pr\u00f3bki s\u0105 najdok\u0142adniejszym ustawieniem.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Sprawdzono na 21 przypadkach o znanym przesuni\u0119ciu: ca\u0142kowite i u\u0142amkowe przesuni\u0119cia trafione z dok\u0142adno\u015bci\u0105 do 0,016 pr\u00f3bki, dwa mikrofony z pog\u0142osem pomieszczenia i szumem (r = 0,32) z dok\u0142adno\u015bci\u0105 do 0,011 pr\u00f3bki, werbel z g\u00f3ry i z do\u0142u z filtrem g\u00f3rnoprzepustowym na dolnym mikrofonie rozpoznany jako przesuni\u0119ty i odwr\u00f3cony. Ton sinusoidalny pozosta\u0142 niejednoznaczny; stopa wzgl\u0119dem basu, perkusja wzgl\u0119dem basu i niezale\u017cny szum da\u0142y brak wsp\u00f3lnego sygna\u0142u. Po zaproponowanym poleceniu ffmpeg \u015bcie\u017cki pokrywa\u0142y si\u0119 we wszystkich siedmiu ponownie zmierzonych przypadkach, a suma zgadza\u0142a si\u0119 z przewidywaniem z dok\u0142adno\u015bci\u0105 do 0,1\u00a0dB. W prawdziwej przegl\u0105darce (Chromium) ta sama \u015bcie\u017cka B jako FLAC, MP3, AAC w M4A i Opus wzgl\u0119dem wersji WAV \u015bcie\u017cki A da\u0142a za ka\u017cdym razem przesuni\u0119cie 64 pr\u00f3bek z dok\u0142adno\u015bci\u0105 do 0,002 pr\u00f3bki: dekoder usuwa wyprzedzenie kodera, a Opus zostaje sprowadzony do cz\u0119stotliwo\u015bci \u015bcie\u017cki A.<\/p>\n<div class=\"vp-h\">Artyku\u0142y na ten temat<\/div>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Jak kompresja sidechain obni\u017ca bas przy ka\u017cdym uderzeniu stopy, zamiast przesuwa\u0107 obie \u015bcie\u017cki wzgl\u0119dem siebie, pokazuje poradnik \u201e<a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/music-production-pl\/tutorials-pl-music-production-pl\/kompresja-sidechain-fl-studio-2026-krok-po-kroku\/\">Kompresja sidechain w FL Studio 2026<\/a>\u201d.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Filtr grzebieniowy, werbel z g\u00f3ry i z do\u0142u oraz stop\u0119 w \u015brodku i na zewn\u0105trz mierzy artyku\u0142 \u201e<span class=\"lw-artikel-geplant\">Przesuni\u0119cie i polaryzacja dw\u00f3ch \u015bcie\u017cek<\/span>\u201d.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Co faza startowa, strojenie, filtr g\u00f3rnoprzepustowy i ducking zmieniaj\u0105 w sumie stopy i basu w najni\u017cszym zakresie, mierzy artyku\u0142 \u201e<span class=\"lw-artikel-geplant\">Stopa i bas w najni\u017cszym zakresie<\/span>\u201d.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Ile op\u00f3\u017anienie mi\u0119dzy lewym a prawym kana\u0142em kosztuje w sumie mono, mierzy artyku\u0142 \u201e<span class=\"lw-artikel-geplant\">Poszerzanie stereo<\/span>\u201d.<\/p>\n<p class=\"vp-klein\" style=\"margin: 0 0 6px;\">Jakie op\u00f3\u017anienie wnosi korektor liniowofazowy, cz\u0119sta przyczyna przesuni\u0119\u0107 w torach r\u00f3wnoleg\u0142ych, mierzy artyku\u0142 \u201e<span class=\"lw-artikel-geplant\">Korektor liniowofazowy a minimalnofazowy<\/span>\u201d.<\/p>\n<p class=\"vp-klein\" style=\"margin: 20px 0 0;\">\u0179r\u00f3d\u0142a:<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;\">Wyszukiwanie obejmuje tylko \u00b1100\u00a0ms; wi\u0119ksze przesuni\u0119cie daje wynik \u201ebrak wsp\u00f3lnego sygna\u0142u\u201d. Przesuni\u0119cie, kt\u00f3re zmienia si\u0119 na d\u0142ugo\u015bci pliku, na przyk\u0142ad przy r\u00f3\u017cnych zegarach dw\u00f3ch urz\u0105dze\u0144, nie ma sta\u0142ego po\u0142o\u017cenia; wynik jest wtedy \u015bredni\u0105 z pierwszych 30\u00a0s. Filtry same op\u00f3\u017aniaj\u0105 sygna\u0142: filtr dolnoprzepustowy 5\u00a0kHz na \u015bcie\u017cce B przesun\u0105\u0142 w te\u015bcie zmierzone po\u0142o\u017cenie o 3,9 pr\u00f3bki, a przesuni\u0119cie \u015bcie\u017cki wyr\u00f3wnuje tak\u017ce to op\u00f3\u017anienie.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';\n    const T = {\"dezimal\":\",\",\"einleitung\":\"Mierzy, o ile druga \u015bcie\u017cka jest przesuni\u0119ta wzgl\u0119dem pierwszej i czy ma odwr\u00f3con\u0105 polaryzacj\u0119: dwa mikrofony przy jednym \u017ar\u00f3dle, DI i wzmacniacz basu, \u015bcie\u017cka przed wtyczk\u0105 z op\u00f3\u017anieniem i po niej. Pokazuje te\u017c, co suma obu \u015bcie\u017cek zyskuje lub traci w ca\u0142ym pa\u015bmie i poni\u017cej 150\u00a0Hz, tak\u017ce dla stopy i basu, kt\u00f3re nie maj\u0105 wsp\u00f3lnego \u017ar\u00f3d\u0142a. Pliki s\u0105 odczytywane w przegl\u0105darce i nie trafiaj\u0105 na serwer.\",\"zone_a\":\"\u015acie\u017cka A (odniesienie)\",\"zone_b\":\"\u015acie\u017cka B (do przesuni\u0119cia)\",\"knopf_datei\":\"Wyb\u00f3r pliku\",\"zone_hinweis\":\"Przy samej \u015bcie\u017cce A w postaci pliku stereo pomiar obejmuje lewy kana\u0142 wzgl\u0119dem prawego. WAV i AIFF s\u0105 odczytywane pr\u00f3bka po pr\u00f3bce; FLAC, MP3, M4A, Ogg i Opus przechodz\u0105 przez dekoder przegl\u0105darki.\",\"knopf_messen\":\"Pomiar\",\"knopf_leeren\":\"Czyszczenie wyboru\",\"status_lesen\":\"Odczyt plik\u00f3w \u2026\",\"status_messen\":\"Pomiar w toku \u2026\",\"k_versatz\":\"Przesuni\u0119cie\",\"k_werte\":\"W pr\u00f3bkach\",\"k_polaritaet\":\"Polaryzacja\",\"k_r\":\"Zgodno\u015b\u0107 r\",\"werte\":\"pr\u00f3bek\",\"pol_gleich\":\"zgodna\",\"pol_gedreht\":\"odwr\u00f3cona\",\"pol_unklar\":\"niejasna\",\"spaeter\":\"B jest op\u00f3\u017aniona o {ms} wzgl\u0119dem A\",\"frueher\":\"B wyprzedza A o {ms}\",\"urteil_deckend\":\"\u015acie\u017cki si\u0119 pokrywaj\u0105\",\"urteil_text_deckend\":\"B le\u017cy pod A z dok\u0142adno\u015bci\u0105 do po\u0142owy pr\u00f3bki i ma t\u0119 sam\u0105 polaryzacj\u0119. Nie ma czego przesuwa\u0107.\",\"urteil_versatz\":\"{lage}\",\"urteil_text_versatz\":\"Po przesuni\u0119ciu o {werte} pr\u00f3bek \u015bcie\u017cki si\u0119 pokrywaj\u0105. Polecenie poni\u017cej przesuwa B za pomoc\u0105 ffmpeg; DAW pozwala przesun\u0105\u0107 \u015bcie\u017ck\u0119 o t\u0119 sam\u0105 liczb\u0119 pr\u00f3bek.\",\"urteil_verpolt\":\"B ma odwr\u00f3con\u0105 polaryzacj\u0119\",\"urteil_text_verpolt\":\"\u015acie\u017cki le\u017c\u0105 we w\u0142a\u015bciwym czasie, ale B jest odwr\u00f3cona: gdy A wychyla si\u0119 w g\u00f3r\u0119, B wychyla si\u0119 w d\u00f3\u0142. Odwr\u00f3cenie polaryzacji B przywraca sum\u0119.\",\"urteil_versatz_verpolt\":\"{lage}, do tego z odwr\u00f3con\u0105 polaryzacj\u0105\",\"urteil_text_versatz_verpolt\":\"Po przesuni\u0119ciu o {werte} pr\u00f3bek i odwr\u00f3ceniu polaryzacji \u015bcie\u017cki si\u0119 pokrywaj\u0105. Polecenie poni\u017cej wykonuje oba kroki.\",\"urteil_mehrdeutig\":\"Przesuni\u0119cie niejednoznaczne\",\"urteil_text_mehrdeutig\":\"Kilka przesuni\u0119\u0107 pasuje niemal r\u00f3wnie dobrze. Tak bywa przy trwa\u0142ych tonach, kt\u00f3rych drganie powtarza si\u0119 z ka\u017cdym okresem; fragment z atakami lub szumem rozstrzyga spraw\u0119.\",\"kandidaten\":\"Mo\u017cliwe przesuni\u0119cia: {liste}.\",\"urteil_kein_bezug\":\"Brak wsp\u00f3lnego sygna\u0142u\",\"urteil_text_kein_bezug\":\"\u015acie\u017cki nie maj\u0105 wsp\u00f3lnego przebiegu, jak stopa i bas albo dwa r\u00f3\u017cne instrumenty. Przesuni\u0119cie jest wtedy niemierzalne. Dla sumy liczy si\u0119 najni\u017cszy zakres: tabela pokazuje, ile suma traci poni\u017cej 150\u00a0Hz w obecnym stanie i przy odwr\u00f3conej polaryzacji B.\",\"hinweis_schwach\":\"Przebiegi zgadzaj\u0105 si\u0119 tylko cz\u0119\u015bciowo (r = {r}), na przyk\u0142ad z powodu pog\u0142osu pomieszczenia, filtr\u00f3w lub zniekszta\u0142ce\u0144. Po\u0142o\u017cenie pochodzi z wybielonej korelacji i to go nie zmienia; suma zyskuje na przesuni\u0119ciu odpowiednio mniej.\",\"hinweis_unklar\":\"Przebieg nie rozstrzyga tu, czy B ma odwr\u00f3con\u0105 polaryzacj\u0119 (r = {r}): filtry przesuwaj\u0105 niskie cz\u0119stotliwo\u015bci inaczej ni\u017c wysokie. Tabela pokazuje, kt\u00f3ra polaryzacja daje g\u0142o\u015bniejsz\u0105 sum\u0119.\",\"hinweis_kerbe\":\"Dop\u00f3ki przesuni\u0119cie istnieje, suma dzia\u0142a jak filtr grzebieniowy z pierwszym wyci\u0119ciem przy {hz} i kolejnymi przy ka\u017cdej nieparzystej wielokrotno\u015bci. {ms} to {cm} drogi d\u017awi\u0119ku w powietrzu.\",\"hinweis_dekodiert\":\"Co najmniej jeden plik przeszed\u0142 przez dekoder przegl\u0105darki i zosta\u0142 zdekodowany z cz\u0119stotliwo\u015bci\u0105 {hz}, wsp\u00f3ln\u0105 dla por\u00f3wnania. Wyprzedzenie MP3 i AAC dekoder usuwa, gdy plik je podaje; przesuni\u0119cie dotyczy wtedy samego d\u017awi\u0119ku.\",\"hinweis_lr\":\"Zmierzono lewy kana\u0142 wzgl\u0119dem prawego w tym samym pliku; B to prawy kana\u0142.\",\"befehl_hinweis\":\"Polecenie przyjmuje B jako b.wav i zapisuje b_korrigiert.wav; atrim przesuwa do przodu, adelay do ty\u0142u, aeval odwraca polaryzacj\u0119.\",\"h_summe\":\"Suma obu \u015bcie\u017cek\",\"sp_fall\":\"Przypadek\",\"sp_gesamt\":\"Suma w ca\u0142ym pa\u015bmie\",\"sp_tief\":\"Poni\u017cej 150\u00a0Hz\",\"sp_fenster\":\"Najs\u0142absze okno 100\u00a0ms poni\u017cej 150\u00a0Hz\",\"fall_jetzt\":\"w obecnym po\u0142o\u017ceniu\",\"fall_gedreht\":\"B odwr\u00f3cona\",\"fall_verschoben\":\"B przesuni\u0119ta o {werte} pr\u00f3bek\",\"fall_verschoben_gedreht\":\"B przesuni\u0119ta i odwr\u00f3cona\",\"kaum_tief\":\"prawie brak basu\",\"summe_hinweis\":\"Poziom sumy wzgl\u0119dem sumy mocy obu \u015bcie\u017cek: +3\u00a0dB oznacza sygna\u0142y identyczne i zgrane, 0\u00a0dB zachowuje si\u0119 jak dwa niezale\u017cne sygna\u0142y, warto\u015bci ujemne to wygaszanie. Zmierzono na odcinku {s}.\",\"knopf_kopieren\":\"Kopiowanie wyniku\",\"kopiert\":\"skopiowano\",\"kopieren_fehler\":\"kopiowanie niemo\u017cliwe\",\"bericht_kopf\":\"Przesuni\u0119cie i polaryzacja\",\"fehler_format\":\"Jeden z plik\u00f3w nie nale\u017cy do odczytywanych tu format\u00f3w: WAV, AIFF, FLAC, MP3, M4A, Ogg i Opus.\",\"fehler_lesen\":\"Odczyt lub dekodowanie jednego z plik\u00f3w zako\u0144czy\u0142o si\u0119 b\u0142\u0119dem.\",\"fehler_kurz\":\"Za ma\u0142o wsp\u00f3lnego materia\u0142u: potrzeba co najmniej 0,25\u00a0s.\",\"fehler_mono\":\"Wybrana jest tylko \u015bcie\u017cka A i jest to plik mono. Pomiar lewego kana\u0142u wzgl\u0119dem prawego wymaga pliku stereo; w innym razie drugi plik trafia jako \u015bcie\u017cka B.\",\"fehler_rate\":\"A i B maj\u0105 r\u00f3\u017cne cz\u0119stotliwo\u015bci pr\u00f3bkowania ({a} i {b}\u00a0Hz). Po sprowadzeniu do wsp\u00f3lnej cz\u0119stotliwo\u015bci nadaj\u0105 si\u0119 do por\u00f3wnania; w innym razie przesuni\u0119cie zmienia si\u0119 na d\u0142ugo\u015bci pliku.\",\"h_erklaerung\":\"Jak przebiega pomiar\",\"erkl_verfahren\":\"Z maksymalnie 30\u00a0s wsp\u00f3lnego materia\u0142u, od 0,1\u00a0s po pocz\u0105tku, obliczana jest korelacja wzajemna obu \u015bcie\u017cek dla przesuni\u0119\u0107 do \u00b1100\u00a0ms. Po\u0142o\u017cenie szczytu pochodzi z wersji wybielonej (SCOT), w kt\u00f3rej ka\u017cda cz\u0119stotliwo\u015b\u0107 liczy si\u0119 tak samo; dzi\u0119ki temu niskie tony i pog\u0142os nie rozmywaj\u0105 szczytu. Warto\u015bci mi\u0119dzy pr\u00f3bkami daje interpolacja sinc z dok\u0142adno\u015bci\u0105 do jednej tysi\u0119cznej pr\u00f3bki. Zgodno\u015b\u0107 i polaryzacja pochodz\u0105 ze zwyk\u0142ej znormalizowanej korelacji w tym miejscu; wa\u017cy ona wed\u0142ug energii, tak jak s\u0142ycha\u0107 sum\u0119.\",\"erkl_summe\":\"Tabela liczy sum\u0119 obu \u015bcie\u017cek w obecnym po\u0142o\u017ceniu, z odwr\u00f3con\u0105 polaryzacj\u0105 B i po przesuni\u0119ciu. Poni\u017cej 150\u00a0Hz obie \u015bcie\u017cki przechodz\u0105 przez ten sam filtr dolnoprzepustowy Butterwortha 4. rz\u0119du. Najs\u0142absze okno 100\u00a0ms obejmuje tylko miejsca, w kt\u00f3rych graj\u0105 obie \u015bcie\u017cki (ka\u017cda najwy\u017cej 20\u00a0dB poni\u017cej najg\u0142o\u015bniejszego okna tej \u015bcie\u017cki); przy stopie i basie to moment, w kt\u00f3rym najni\u017cszy zakres wygasza si\u0119 najsilniej.\",\"erkl_polaritaet\":\"Odwr\u00f3cenie polaryzacji zmienia znak ka\u017cdej pr\u00f3bki i dzia\u0142a na wszystkie cz\u0119stotliwo\u015bci jednakowo. Przesuni\u0119cie natomiast obraca faz\u0119 r\u00f3\u017cnie dla ka\u017cdej cz\u0119stotliwo\u015bci: przy 1\u00a0ms pierwsze wygaszenie wypada przy 500\u00a0Hz, nast\u0119pne przy 1,5\u00a0kHz. Dlatego odwr\u00f3cona polaryzacja nie zast\u0119puje przesuni\u0119cia. D\u017awi\u0119k w powietrzu przy 20 \u00b0C pokonuje 344 m\\\/s, wi\u0119c 1\u00a0ms odpowiada 34,4 cm odleg\u0142o\u015bci mi\u0119dzy dwoma mikrofonami.\",\"erkl_daw\":\"W FL Studio Fruity Stereo Shaper odwraca polaryzacj\u0119 jednego lub obu kana\u0142\u00f3w i op\u00f3\u017ania jeden kana\u0142 wzgl\u0119dem drugiego; wed\u0142ug podr\u0119cznika kompensacj\u0119 op\u00f3\u017anienia \u015bcie\u017cki miksera FL Studio przyjmuje tak\u017ce r\u0119cznie w milisekundach lub pr\u00f3bkach, przy czym pr\u00f3bki s\u0105 najdok\u0142adniejszym ustawieniem.\",\"erkl_messung\":\"Sprawdzono na 21 przypadkach o znanym przesuni\u0119ciu: ca\u0142kowite i u\u0142amkowe przesuni\u0119cia trafione z dok\u0142adno\u015bci\u0105 do 0,016 pr\u00f3bki, dwa mikrofony z pog\u0142osem pomieszczenia i szumem (r = 0,32) z dok\u0142adno\u015bci\u0105 do 0,011 pr\u00f3bki, werbel z g\u00f3ry i z do\u0142u z filtrem g\u00f3rnoprzepustowym na dolnym mikrofonie rozpoznany jako przesuni\u0119ty i odwr\u00f3cony. Ton sinusoidalny pozosta\u0142 niejednoznaczny; stopa wzgl\u0119dem basu, perkusja wzgl\u0119dem basu i niezale\u017cny szum da\u0142y brak wsp\u00f3lnego sygna\u0142u. Po zaproponowanym poleceniu ffmpeg \u015bcie\u017cki pokrywa\u0142y si\u0119 we wszystkich siedmiu ponownie zmierzonych przypadkach, a suma zgadza\u0142a si\u0119 z przewidywaniem z dok\u0142adno\u015bci\u0105 do 0,1\u00a0dB. W prawdziwej przegl\u0105darce (Chromium) ta sama \u015bcie\u017cka B jako FLAC, MP3, AAC w M4A i Opus wzgl\u0119dem wersji WAV \u015bcie\u017cki A da\u0142a za ka\u017cdym razem przesuni\u0119cie 64 pr\u00f3bek z dok\u0142adno\u015bci\u0105 do 0,002 pr\u00f3bki: dekoder usuwa wyprzedzenie kodera, a Opus zostaje sprowadzony do cz\u0119stotliwo\u015bci \u015bcie\u017cki A.\",\"h_artikel\":\"Artyku\u0142y na ten temat\",\"art_sidechain_vor\":\"Jak kompresja sidechain obni\u017ca bas przy ka\u017cdym uderzeniu stopy, zamiast przesuwa\u0107 obie \u015bcie\u017cki wzgl\u0119dem siebie, pokazuje poradnik \u201e\",\"art_sidechain_titel\":\"Kompresja sidechain w FL Studio 2026\",\"art_sidechain_nach\":\"\u201d.\",\"art_versatz_vor\":\"Filtr grzebieniowy, werbel z g\u00f3ry i z do\u0142u oraz stop\u0119 w \u015brodku i na zewn\u0105trz mierzy artyku\u0142 \u201e\",\"art_versatz_titel\":\"Przesuni\u0119cie i polaryzacja dw\u00f3ch \u015bcie\u017cek\",\"art_versatz_nach\":\"\u201d.\",\"art_kickbass_vor\":\"Co faza startowa, strojenie, filtr g\u00f3rnoprzepustowy i ducking zmieniaj\u0105 w sumie stopy i basu w najni\u017cszym zakresie, mierzy artyku\u0142 \u201e\",\"art_kickbass_titel\":\"Stopa i bas w najni\u017cszym zakresie\",\"art_kickbass_nach\":\"\u201d.\",\"art_stereo_vor\":\"Ile op\u00f3\u017anienie mi\u0119dzy lewym a prawym kana\u0142em kosztuje w sumie mono, mierzy artyku\u0142 \u201e\",\"art_stereo_titel\":\"Poszerzanie stereo\",\"art_stereo_nach\":\"\u201d.\",\"art_eq_vor\":\"Jakie op\u00f3\u017anienie wnosi korektor liniowofazowy, cz\u0119sta przyczyna przesuni\u0119\u0107 w torach r\u00f3wnoleg\u0142ych, mierzy artyku\u0142 \u201e\",\"art_eq_titel\":\"Korektor liniowofazowy a minimalnofazowy\",\"art_eq_nach\":\"\u201d.\",\"quellen_titel\":\"\u0179r\u00f3d\u0142a\",\"grenze\":\"Wyszukiwanie obejmuje tylko \u00b1100\u00a0ms; wi\u0119ksze przesuni\u0119cie daje wynik \u201ebrak wsp\u00f3lnego sygna\u0142u\u201d. Przesuni\u0119cie, kt\u00f3re zmienia si\u0119 na d\u0142ugo\u015bci pliku, na przyk\u0142ad przy r\u00f3\u017cnych zegarach dw\u00f3ch urz\u0105dze\u0144, nie ma sta\u0142ego po\u0142o\u017cenia; wynik jest wtedy \u015bredni\u0105 z pierwszych 30\u00a0s. Filtry same op\u00f3\u017aniaj\u0105 sygna\u0142: filtr dolnoprzepustowy 5\u00a0kHz na \u015bcie\u017cce B przesun\u0105\u0142 w te\u015bcie zmierzone po\u0142o\u017cenie o 3,9 pr\u00f3bki, a przesuni\u0119cie \u015bcie\u017cki wyr\u00f3wnuje tak\u017ce to op\u00f3\u017anienie.\"};<\/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>Mierzy przesuni\u0119cie mi\u0119dzy dwiema \u015bcie\u017ckami albo mi\u0119dzy lewym a prawym kana\u0142em z dok\u0142adno\u015bci\u0105 do u\u0142amka pr\u00f3bki, wykrywa odwr\u00f3con\u0105 polaryzacj\u0119 i liczy, co suma zyskuje lub traci w ca\u0142ym pa\u015bmie i poni\u017cej 150\u00a0Hz. Podaje polecenie ffmpeg, kt\u00f3re przesuwa i odwraca drug\u0105 \u015bcie\u017ck\u0119.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92906],"class_list":["post-20242","page","type-page","status-publish","hentry","tag-music-production-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - 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\/pl\/narzedzia\/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=\"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Mierzy przesuni\u0119cie mi\u0119dzy dwiema \u015bcie\u017ckami albo mi\u0119dzy lewym a prawym kana\u0142em z dok\u0142adno\u015bci\u0105 do u\u0142amka pr\u00f3bki, wykrywa odwr\u00f3con\u0105 polaryzacj\u0119 i liczy, co suma zyskuje lub traci w ca\u0142ym pa\u015bmie i poni\u017cej 150\u00a0Hz. Podaje polecenie ffmpeg, kt\u00f3re przesuwa i odwraca drug\u0105 \u015bcie\u017ck\u0119.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/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:49+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\\\/pl\\\/narzedzia\\\/time-offset-polarity-checker-two-tracks\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/time-offset-polarity-checker-two-tracks\\\/\",\"name\":\"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-23T19:38:02+00:00\",\"dateModified\":\"2026-09-23T19:59:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/time-offset-polarity-checker-two-tracks\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/time-offset-polarity-checker-two-tracks\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/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-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek\"}]},{\"@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":"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - 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\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/","og_locale":"en_US","og_type":"article","og_title":"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - Lukas Wojcik - Blog","og_description":"Mierzy przesuni\u0119cie mi\u0119dzy dwiema \u015bcie\u017ckami albo mi\u0119dzy lewym a prawym kana\u0142em z dok\u0142adno\u015bci\u0105 do u\u0142amka pr\u00f3bki, wykrywa odwr\u00f3con\u0105 polaryzacj\u0119 i liczy, co suma zyskuje lub traci w ca\u0142ym pa\u015bmie i poni\u017cej 150\u00a0Hz. Podaje polecenie ffmpeg, kt\u00f3re przesuwa i odwraca drug\u0105 \u015bcie\u017ck\u0119.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-09-23T19:59:49+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\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/","name":"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-23T19:38:02+00:00","dateModified":"2026-09-23T19:59:49+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/time-offset-polarity-checker-two-tracks\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/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-3\/"},{"@type":"ListItem","position":3,"name":"Przesuni\u0119cie i polaryzacja: przesuni\u0119cie czasowe i odwr\u00f3cona polaryzacja dw\u00f3ch \u015bcie\u017cek"}]},{"@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\/20242","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=20242"}],"version-history":[{"count":3,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20242\/revisions"}],"predecessor-version":[{"id":20309,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20242\/revisions\/20309"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=20242"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}