{"id":20129,"date":"2026-09-23T18:48:18","date_gmt":"2026-09-23T16:48:18","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/"},"modified":"2026-09-23T18:54:14","modified_gmt":"2026-09-23T16:54:14","slug":"release-file-checker-sample-rate-bit-depth-peaks-isrc-cover","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/","title":{"rendered":"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen"},"content":{"rendered":"<div class=\"lw-rp\" id=\"rp-wurzel\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<style>\n.lw-rp { --rp-warn: #e8a33d; }\n:root[data-theme=\"light\"] .lw-rp { --rp-warn: #8f5300; }\n.lw-rp .rp-zone { border: 2px dashed var(--border, #2a2a35); border-radius: 8px; padding: 22px; text-align: center; }\n.lw-rp .rp-zone.rp-ueber { border-color: var(--accent, #2ba6df); }\n.lw-rp .rp-gesamt { border-radius: 8px; padding: 12px 15px; margin-top: 4px; border: 1px solid var(--border, #2a2a35); background: var(--bg-body, #14141a); }\n.lw-rp .rp-gesamt-kopf { font-weight: 700; color: var(--text-primary, #e8e8ee); margin-bottom: 4px; }\n.lw-rp .rp-g-ok .rp-gesamt-kopf { color: var(--ok, #7ee787); }\n.lw-rp .rp-g-hinweis .rp-gesamt-kopf { color: var(--rp-warn); }\n.lw-rp .rp-g-problem .rp-gesamt-kopf { color: var(--fehler, #f0857a); }\n.lw-rp .rp-tabelle { overflow-x: auto; margin-top: 6px; }\n.lw-rp table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }\n.lw-rp th, .lw-rp td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--border, #2a2a35); vertical-align: top; }\n.lw-rp th { color: var(--text-primary, #e8e8ee); white-space: nowrap; }\n.lw-rp td { color: var(--text-primary, #e8e8ee); }\n.lw-rp td.rp-wert { font-family: monospace; color: var(--text-secondary, #a0a0b0); white-space: nowrap; }\n.lw-rp td.rp-text { color: var(--text-secondary, #a0a0b0); line-height: 1.5; }\n.lw-rp .rp-stufe { display: inline-block; font-size: 0.74rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; padding: 2px 7px; border-radius: 4px; border: 1px solid currentColor; white-space: nowrap; }\n.lw-rp .rp-s-ok { color: var(--ok, #7ee787); }\n.lw-rp .rp-s-hinweis { color: var(--rp-warn); }\n.lw-rp .rp-s-problem { color: var(--fehler, #f0857a); }\n.lw-rp .rp-s-info, .lw-rp .rp-s-offen { color: var(--text-secondary, #a0a0b0); }\n.lw-rp .rp-h { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 24px 0 8px; }\n.lw-rp .rp-klein { font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); line-height: 1.55; }\n.lw-rp .rp-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: 14px; }\n.lw-rp .rp-name { margin-top: 4px; }\n.lw-rp .rp-fehler { color: var(--fehler, #f0857a); font-size: 0.88rem; margin-top: 12px; }\n.lw-rp a { color: var(--accent, #2ba6df); }\n@media (max-width: 480px) {\n    .lw-rp th, .lw-rp td { padding: 6px 5px; }\n    .lw-rp td.rp-wert { white-space: normal; word-break: break-word; }\n}\n\/* Schmal: die Checkliste als gestapelte Karten, sonst wird der Befund abgeschnitten. *\/\n@media (max-width: 600px) {\n    .lw-rp table.rp-karten thead { display: none; }\n    .lw-rp table.rp-karten tr { display: block; padding: 9px 0; border-bottom: 1px solid var(--border, #2a2a35); }\n    .lw-rp table.rp-karten td { display: block; border: none; padding: 2px 2px; }\n    .lw-rp table.rp-karten td.rp-wert { white-space: normal; margin-top: 3px; }\n    .lw-rp table.rp-karten .rp-name { display: inline; margin: 0 0 0 7px; font-weight: 700; }\n}\n<\/style>\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 18px;\">Pr\u00fcft eine Audiodatei, bevor sie an einen Vertrieb geht: Format, Samplerate und Bit-Tiefe gegen die Lieferanforderungen von Apple, Bits, die die Datei nur auff\u00fcllen, Clipping, True Peak, Gleichanteil, Stille am Anfang und am Ende sowie Titel, K\u00fcnstler, ISRC und Cover aus den Tags. Die Datei wird im Browser gelesen und nicht hochgeladen.<\/p>\n<div id=\"rp-zone\" class=\"rp-zone\">\n<p style=\"margin: 0 0 12px; color: var(--text-primary, #e8e8ee); font-weight: 700;\">Release-Datei ausw\u00e4hlen<\/p>\n<p>        <button id=\"rp-knopf\" type=\"button\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 11px 22px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Datei w\u00e4hlen<\/button><br \/>\n        <input id=\"rp-datei\" type=\"file\" accept=\"audio\/*,.wav,.wave,.aif,.aiff,.aifc,.flac,.mp3,.m4a,.mp4,.aac,.ogg,.oga,.opus\" hidden><\/p>\n<p class=\"rp-klein\" style=\"margin: 12px 0 0;\">WAV, RF64, AIFF, FLAC, MP3, M4A, Ogg Vorbis und Opus. WAV und AIFF werden Wert f\u00fcr Wert gelesen, die \u00fcbrigen Formate laufen \u00fcber den Decoder des Browsers.<\/p>\n<\/p><\/div>\n<div id=\"rp-status\" class=\"rp-klein\" data-mp-mask style=\"margin-top: 12px;\" aria-live=\"polite\"><\/div>\n<div id=\"rp-fehler\" class=\"rp-fehler\" data-mp-mask hidden><\/div>\n<div id=\"rp-ausgabe\" data-mp-mask style=\"margin-top: 18px;\" aria-live=\"polite\" hidden>\n<div id=\"rp-gesamt\" class=\"rp-gesamt\"><\/div>\n<div class=\"rp-h\">Checkliste<\/div>\n<div class=\"rp-tabelle\">\n<table class=\"rp-karten\">\n<thead>\n<tr>\n<th>Pr\u00fcfpunkt<\/th>\n<th>Wert<\/th>\n<th>Befund<\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"rp-liste\"><\/tbody>\n<\/table><\/div>\n<div class=\"rp-h\">Tags in der Datei<\/div>\n<div class=\"rp-tabelle\">\n<table>\n<thead>\n<tr>\n<th>Feld<\/th>\n<th>Wert<\/th>\n<th>Abgelegt in<\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"rp-tags\"><\/tbody>\n<\/table><\/div>\n<p>        <button id=\"rp-kopieren\" type=\"button\" class=\"rp-knopf\">Ergebnis kopieren<\/button><br \/>\n        <span id=\"rp-kopiert\" class=\"rp-klein\" style=\"margin-left: 10px;\"><\/span>\n    <\/div>\n<div class=\"rp-h\">Was gepr\u00fcft wird und warum<\/div>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Apple Music nimmt Ton mit 44,1, 48, 88,2, 96, 176,4 oder 192\u00a0kHz bei 16 oder 24\u00a0Bit und bittet um den Master in der h\u00f6chsten verf\u00fcgbaren Aufl\u00f6sung. Eine verlustbehaftete Datei erf\u00fcllt das nicht: Der Encoder hat Teile des Signals schon verworfen, und der Dienst kodiert noch einmal.<\/p>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Genutzte Bits: F\u00fcr jeden Wert werden die untersten Bits gepr\u00fcft. Sind sie in der ganzen Datei null, tr\u00e4gt die zus\u00e4tzliche Tiefe nichts, etwa bei einem 16-Bit-Master, der als 24\u00a0Bit gespeichert wurde. Apple Digital Masters schlie\u00dft dieses Auff\u00fcllen ausdr\u00fccklich aus. In Gleitkommadateien fragt die Pr\u00fcfung, ob jeder Wert auf dem 16- oder dem 24-Bit-Raster liegt.<\/p>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Vollaussteuerung ist der h\u00f6chste Ganzzahlwert; drei oder mehr solche Werte hintereinander z\u00e4hlen als geclippte Stelle. Der True Peak folgt ITU-R BS.1770 mit dem Filter aus 48 Koeffizienten bei vierfacher \u00dcberabtastung. Er findet Spitzen zwischen den Abtastwerten, die eine Wandlung oder ein Encoder zu echten macht.<\/p>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Stille hei\u00dft hier unter \u221260\u00a0dBFS. Die Grenzen von einer Sekunde am Anfang, f\u00fcnf Sekunden am Ende, \u221240\u00a0dBFS f\u00fcr den ersten und den letzten Wert und \u221260\u00a0dBFS f\u00fcr den Gleichanteil sind Regeln dieser Pr\u00fcfung, keine Vorgaben eines Dienstes. Diese Grenzen markieren, was vor dem Hochladen ein Anh\u00f6ren lohnt.<\/p>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Gelesen werden ID3v2 und ID3v1, Vorbis-Kommentare in FLAC, Ogg und Opus, RIFF INFO und ID3-Chunks in WAV und AIFF sowie die MP4-Metadaten. Beim ISRC entscheidet das Feld: TSRC in ID3, ISRC in Vorbis-Kommentaren. ffmpeg schreibt bei -metadata ISRC=\u2026 andere Felder, wie der Artikel zu Release-Metadaten gemessen hat.<\/p>\n<p class=\"rp-klein\" style=\"margin: 0 0 6px;\">Apple empfiehlt 3000\u00a0\u00d7\u00a03000\u00a0Pixel oder mehr, verlangt mindestens 1400\u00a0\u00d7\u00a01400 und ein quadratisches Bild als JPEG oder PNG. Gepr\u00fcft wird das eingebettete Bild; das Cover f\u00fcr den Vertrieb ist eine eigene Datei.<\/p>\n<p class=\"rp-klein\" style=\"margin: 20px 0 0;\">Quellen:<br \/>\n        <a href=\"https:\/\/itunespartner.apple.com\/music\/support\/5215-digital-packaging-music\" rel=\"noopener\">Apple Music Provider Support: Digital packaging for music<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/www.apple.com\/apple-music\/apple-digital-masters\/docs\/apple-digital-masters.pdf\" rel=\"noopener\">Apple Digital Masters<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/www.itu.int\/rec\/R-REC-BS.1770\" rel=\"noopener\">ITU-R BS.1770<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/aes2.org\/wp-content\/uploads\/2024\/01\/20210924_TD1008_v3.13.pdf\" rel=\"noopener\">AES TD1008<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/isrc.ifpi.org\/images\/downloads\/ISRC_Handbook.pdf\" rel=\"noopener\">ISRC Handbook<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/mutagen-specs.readthedocs.io\/en\/latest\/id3\/id3v2.4.0-frames.html\" rel=\"noopener\">ID3v2.4 frames<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/xiph.org\/vorbis\/doc\/v-comment.html\" rel=\"noopener\">Vorbis comment<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/exiftool.org\/TagNames\/RIFF.html\" rel=\"noopener\">RIFF Tags (ExifTool)<\/a>\n    <\/p>\n<p class=\"rp-klein\" style=\"font-size: 0.8rem; margin: 14px 0 0;\">Die genannten Anforderungen sind die von Apple; andere Vertriebe ver\u00f6ffentlichen eigene. Formate au\u00dfer WAV und AIFF h\u00e4ngen am Decoder des Browsers, der in manchen Browsern ALAC oder komprimiertes AIFC nicht liest. Die Lautheit misst das LUFS-Messger\u00e4t.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';\n    const T = {\"dezimal\":\",\",\"tausender\":\"\",\"einleitung\":\"Pr\u00fcft eine Audiodatei, bevor sie an einen Vertrieb geht: Format, Samplerate und Bit-Tiefe gegen die Lieferanforderungen von Apple, Bits, die die Datei nur auff\u00fcllen, Clipping, True Peak, Gleichanteil, Stille am Anfang und am Ende sowie Titel, K\u00fcnstler, ISRC und Cover aus den Tags. Die Datei wird im Browser gelesen und nicht hochgeladen.\",\"zone_titel\":\"Release-Datei ausw\u00e4hlen\",\"knopf_datei\":\"Datei w\u00e4hlen\",\"zone_hinweis\":\"WAV, RF64, AIFF, FLAC, MP3, M4A, Ogg Vorbis und Opus. WAV und AIFF werden Wert f\u00fcr Wert gelesen, die \u00fcbrigen Formate laufen \u00fcber den Decoder des Browsers.\",\"h_liste\":\"Checkliste\",\"sp_pruefpunkt\":\"Pr\u00fcfpunkt\",\"sp_wert\":\"Wert\",\"sp_befund\":\"Befund\",\"h_tags\":\"Tags in der Datei\",\"sp_feld\":\"Feld\",\"sp_ort\":\"Abgelegt in\",\"status_lesen\":\"Datei wird gelesen \u2026\",\"status_dekodieren\":\"Wird dekodiert \u2026\",\"status_messen\":\"Messung l\u00e4uft \u2026 {p}\u00a0%\",\"gesamt_ok\":\"Keine Probleme, keine Hinweise\",\"gesamt_hinweis\":\"Keine Probleme \u00b7 Hinweise: {h}\",\"gesamt_problem\":\"Probleme: {p} \u00b7 Hinweise: {h}\",\"gesamt_text_ok\":\"Alles, was hier gemessen wird, erf\u00fcllt die Anforderungen aus den Quellen. Was ein Vertrieb dar\u00fcber hinaus pr\u00fcft, etwa die Angaben im Upload-Formular, steht nicht in dieser Datei.\",\"gesamt_text_hinweis\":\"Nichts steht der Lieferung im Weg, die Hinweise verdienen vor dem Hochladen aber einen Blick.\",\"gesamt_text_problem\":\"Mindestens ein Punkt widerspricht einer Lieferanforderung oder deutet auf einen Schaden in der Datei. Welcher, steht in den Befunden.\",\"stufe_ok\":\"OK\",\"stufe_hinweis\":\"Hinweis\",\"stufe_problem\":\"Problem\",\"stufe_info\":\"Info\",\"stufe_offen\":\"Nicht gemessen\",\"p_format\":\"Format\",\"p_rate\":\"Samplerate\",\"p_bits\":\"Bit-Tiefe\",\"p_wirksam\":\"Genutzte Bits\",\"p_kanaele\":\"Kan\u00e4le\",\"p_messung\":\"Ton\",\"p_dauer\":\"Dauer\",\"p_spitze\":\"Sample-Spitze\",\"p_clipping\":\"Geclippte Stellen\",\"p_ueber\":\"Werte \u00fcber 0\u00a0dBFS\",\"p_truepeak\":\"True Peak\",\"p_dc\":\"Gleichanteil\",\"p_stille_anfang\":\"Stille am Anfang\",\"p_stille_ende\":\"Stille am Ende\",\"p_sprung\":\"Erster und letzter Wert\",\"p_kanalvergleich\":\"Links gegen rechts\",\"p_titel\":\"Titel\",\"p_kuenstler\":\"K\u00fcnstler\",\"p_isrc\":\"ISRC\",\"p_cover\":\"Cover\",\"wert_float\":\"Gleitkomma\",\"wert_keine_tags\":\"Kein Titel, K\u00fcnstler, ISRC oder Cover gefunden\",\"bericht_kopf\":\"Release-Datei-Pr\u00fcfung\",\"f_titel\":\"Titel\",\"f_kuenstler\":\"K\u00fcnstler\",\"f_isrc\":\"ISRC\",\"f_cover\":\"Cover\",\"ort_id3\":\"ID3v2-Tag\",\"ort_id3v1\":\"ID3v1-Tag\",\"ort_tsrc\":\"ID3-Rahmen TSRC\",\"ort_txxx\":\"ID3-Rahmen TXXX:ISRC\",\"ort_vorbis\":\"Vorbis-Kommentar\",\"ort_vorbis_bild\":\"Vorbis-Kommentar METADATA_BLOCK_PICTURE\",\"ort_flac_bild\":\"FLAC-Block PICTURE\",\"ort_riff\":\"RIFF INFO\",\"ort_riff_isrc\":\"RIFF-INFO-Feld ISRC\",\"ort_aiff\":\"AIFF-Chunk\",\"ort_mp4\":\"MP4-Tag\",\"ort_mdta\":\"QuickTime-Metadatenschl\u00fcssel\",\"ort_mp4_frei\":\"MP4-Freiformfeld ISRC\",\"b_format_verlustfrei\":\"{format} speichert den Ton verlustfrei.\",\"b_format_verlustbehaftet\":\"{format} ist verlustbehaftet. Apple bittet um den Master in der h\u00f6chsten verf\u00fcgbaren Aufl\u00f6sung, und eine verlustbehaftete Datei kann das nicht sein.\",\"b_format_unbekannt\":\"Der Container {format} wurde erkannt, der Codec darin nicht.\",\"b_offen_kopf\":\"Der Dateikopf nennt diesen Wert nicht.\",\"b_rate_ok\":\"{rate} geh\u00f6rt zu den Raten, die Apple annimmt: 44,1, 48, 88,2, 96, 176,4 und 192\u00a0kHz.\",\"b_rate_andere\":\"{rate} geh\u00f6rt nicht zu den Raten, die Apple annimmt (44,1, 48, 88,2, 96, 176,4 und 192\u00a0kHz). Vor der Lieferung ist eine Wandlung f\u00e4llig.\",\"b_bits_verlustbehaftet\":\"Ein verlustbehaftetes Format hat keine feste Bit-Tiefe; der Decoder liefert Gleitkommawerte.\",\"b_bits_float\":\"Gleitkomma mit {bits}\u00a0Bit. Apple nennt 16 und 24\u00a0Bit, vor der Lieferung steht also eine Wandlung auf 24\u00a0Bit Ganzzahl an.\",\"b_bits_24\":\"24\u00a0Bit, wie Apple es f\u00fcr Apple Digital Masters empfiehlt.\",\"b_bits_16\":\"16\u00a0Bit werden angenommen. F\u00fcr Apple Digital Masters verlangt Apple 24-Bit-Quellen.\",\"b_bits_wenig\":\"{bits}\u00a0Bit sind weniger als die 16 oder 24\u00a0Bit, die Apple annimmt.\",\"b_bits_andere\":\"{bits}\u00a0Bit Ganzzahl geh\u00f6rt nicht zu den Tiefen, die Apple nennt (16 und 24\u00a0Bit).\",\"b_wirksam_stille\":\"Die Datei enth\u00e4lt nur digitale Stille; welche Bits genutzt werden, l\u00e4sst sich so nicht bestimmen.\",\"b_wirksam_float16\":\"Jeder Wert liegt genau auf dem 16-Bit-Raster: ein 16-Bit-Signal in einer Gleitkommadatei. Die zus\u00e4tzliche Genauigkeit ist leer.\",\"b_wirksam_float24\":\"Jeder Wert liegt genau auf dem 24-Bit-Raster, eine Wandlung auf 24\u00a0Bit Ganzzahl verliert also nichts.\",\"b_wirksam_float\":\"Die Werte nutzen die Gleitkommagenauigkeit; eine Wandlung auf 24\u00a0Bit braucht Dither.\",\"b_wirksam_offen\":\"F\u00fcr diese Datei nicht bestimmbar.\",\"b_wirksam_voll\":\"Alle {bits}\u00a0Bit tragen Signal.\",\"b_wirksam_aufgefuellt\":\"Nur {wirksam} von {bits}\u00a0Bit tragen Signal, die \u00fcbrigen sind immer null. Die Datei ist ein {wirksam}-Bit-Signal, auf {bits}\u00a0Bit aufgef\u00fcllt \u2013 genau das schlie\u00dft Apple Digital Masters ausdr\u00fccklich aus.\",\"b_wirksam_weniger\":\"Nur {wirksam} von {bits}\u00a0Bit tragen Signal; die untersten Bits sind immer null.\",\"b_kanaele_2\":\"Stereo.\",\"b_kanaele_1\":\"Mono. Ob ein Vertrieb eine Monodatei nimmt oder zwei gleiche Kan\u00e4le erwartet, steht in seiner eigenen Spezifikation.\",\"b_kanaele_mehr\":\"{n} Kan\u00e4le. Ein Mehrkanal-Mix wie Dolby Atmos wird getrennt geliefert und bekommt einen eigenen ISRC.\",\"b_offen_ton\":\"Der Browser konnte den Ton dieser Datei nicht dekodieren; Spitzen, Stille und Gleichanteil sind deshalb nicht gemessen. Kopf und Tags stehen trotzdem da.\",\"b_dauer\":\"L\u00e4nge des Tons, wie er in der Datei steht.\",\"b_spitze_ok\":\"Der h\u00f6chste Wert bleibt unter der Vollaussteuerung.\",\"b_spitze_voll\":\"Werte auf Vollaussteuerung: {n}. Ob das Clipping ist, zeigt die n\u00e4chste Zeile.\",\"b_clipping_keine\":\"Keine Folge von drei oder mehr Werten auf Vollaussteuerung.\",\"b_clipping\":\"Stellen mit drei oder mehr aufeinanderfolgenden Werten auf Vollaussteuerung: {n}. Dort ist die Wellenform flach abgeschnitten.\",\"b_ueber_keine\":\"Kein Wert liegt \u00fcber der Vollaussteuerung.\",\"b_ueber\":\"Werte \u00fcber 0\u00a0dBFS: {n}. Eine Gleitkommadatei kann sie halten, die Wandlung in Ganzzahl-PCM schneidet sie ab.\",\"b_tp_ok\":\"H\u00f6chstens \u22121\u00a0dBTP, wie AES TD1008 es am Eingang eines Codecs empfiehlt.\",\"b_tp_hinweis\":\"Zwischen \u22121 und 0\u00a0dBTP. AES TD1008 empfiehlt am Eingang des Codecs h\u00f6chstens \u22121\u00a0dBTP, weil das Kodieren die Spitzen weiter anhebt.\",\"b_tp_problem\":\"\u00dcber 0\u00a0dBTP: Zwischen den Abtastwerten \u00fcberschreitet die Wellenform schon die Vollaussteuerung, und jede Wandlung oder Kodierung kann sie clippen.\",\"b_dc_ok\":\"Kein nennenswerter Gleichanteil (Grenze dieser Pr\u00fcfung: \u221260\u00a0dBFS).\",\"b_dc_hoch\":\"Der Mittelwert liegt bei \u221260\u00a0dBFS oder dar\u00fcber. Ein Gleichanteil kostet Aussteuerungsreserve und macht Anfang und Ende der Datei zu einer Stufe.\",\"b_stille_ganz\":\"Die Datei enth\u00e4lt keinen Wert \u00fcber \u221260\u00a0dBFS.\",\"b_stille_anfang_ok\":\"Zeit bis zum ersten Wert \u00fcber \u221260\u00a0dBFS.\",\"b_stille_anfang_lang\":\"Bis zum ersten Wert \u00fcber \u221260\u00a0dBFS vergeht mindestens eine Sekunde, und ein Player spielt diese Stille vor der Musik ab.\",\"b_stille_ende_ok\":\"Zeit nach dem letzten Wert \u00fcber \u221260\u00a0dBFS.\",\"b_stille_ende_lang\":\"Nach dem letzten Wert \u00fcber \u221260\u00a0dBFS bleiben mindestens f\u00fcnf Sekunden; auf einem Album verl\u00e4ngern sie die Pause vor dem n\u00e4chsten Titel.\",\"b_sprung_ok\":\"Die Datei beginnt und endet unter \u221240\u00a0dBFS, die Wiedergabe setzt also ohne Stufe ein und h\u00f6rt ohne Stufe auf.\",\"b_sprung_anfang\":\"Der erste Wert liegt bei \u221240\u00a0dBFS oder dar\u00fcber. Die Wiedergabe beginnt mit einem Sprung aus der Stille auf diesen Wert, h\u00f6rbar als Knacken.\",\"b_sprung_ende\":\"Der letzte Wert liegt bei \u221240\u00a0dBFS oder dar\u00fcber. Die Wiedergabe endet mit einem Sprung in die Stille, h\u00f6rbar als Knacken.\",\"b_sprung_beide\":\"Erster und letzter Wert liegen bei \u221240\u00a0dBFS oder dar\u00fcber: Spr\u00fcnge an beiden Enden, h\u00f6rbar als Knacken.\",\"b_kanal_ok\":\"Die Kan\u00e4le unterscheiden sich, und beide tragen Signal.\",\"b_kanal_gleich\":\"Links und rechts sind Wert f\u00fcr Wert gleich: ein Monosignal in einer Stereodatei.\",\"b_kanal_stumm\":\"Kanal {kanal} ist stumm, w\u00e4hrend der andere Signal tr\u00e4gt.\",\"b_titel_da\":\"Gefunden in: {ort}.\",\"b_titel_fehlt\":\"Kein Titel in der Datei. Der Vertrieb \u00fcbernimmt den Titel aus seinem Upload-Formular; ein Tag hilft \u00fcberall dort, wo die Datei allein unterwegs ist.\",\"b_kuenstler_da\":\"Gefunden in: {ort}.\",\"b_kuenstler_fehlt\":\"Kein K\u00fcnstler in der Datei. Auch hier z\u00e4hlt beim Vertrieb das Upload-Formular; sonst begleitet der Tag die Datei \u00fcberallhin.\",\"b_isrc_ok\":\"Wohlgeformter Code, abgelegt im daf\u00fcr vorgesehenen Feld ({ort}).\",\"b_isrc_txxx\":\"Der Code steht in einem TXXX-Rahmen namens ISRC \u2013 das schreibt ffmpeg bei -metadata ISRC=\u2026. ID3v2.4 sieht daf\u00fcr den Rahmen TSRC vor.\",\"b_isrc_riff\":\"Das RIFF-INFO-Feld ISRC steht laut Tag-Referenz von ExifTool f\u00fcr \u201eSource\u201c, nicht f\u00fcr den Aufnahmecode. Ein Programm, das diese Datei liest, kann sich darauf nicht verlassen.\",\"b_isrc_form\":\"Der Wert ({ort}) ist kein wohlgeformter ISRC: zwei Buchstaben, drei Buchstaben oder Ziffern, zwei Ziffern f\u00fcr das Jahr und f\u00fcnf Ziffern.\",\"b_isrc_mehrere\":\"Die Datei tr\u00e4gt {n} verschiedene ISRCs. Laut ISRC-Handbuch hat eine Aufnahme genau einen.\",\"b_isrc_fehlt\":\"Kein ISRC in der Datei. Laut ISRC-Handbuch soll der Code nach M\u00f6glichkeit mit der Aufnahme zusammen kodiert werden; der Vertrieb liefert ihn zus\u00e4tzlich \u00fcber DDEX.\",\"b_cover_fehlt\":\"Kein eingebettetes Cover. Vertriebe nehmen das Cover als eigenen Upload entgegen.\",\"b_cover_format\":\"Das eingebettete Bild ist {typ}; Apple nimmt JPEG oder PNG.\",\"b_cover_masse\":\"Die Bildgr\u00f6\u00dfe lie\u00df sich aus der eingebetteten Datei nicht lesen.\",\"b_cover_quadrat\":\"{breite}\u00a0\u00d7\u00a0{hoehe}\u00a0px ist nicht quadratisch; Apple verlangt ein Seitenverh\u00e4ltnis von 1:1.\",\"b_cover_klein\":\"{breite}\u00a0\u00d7\u00a0{hoehe}\u00a0px liegt unter Apples Mindestma\u00df von 1400\u00a0\u00d7\u00a01400\u00a0px.\",\"b_cover_mittel\":\"\u00dcber Apples Mindestma\u00df von 1400\u00a0\u00d7\u00a01400\u00a0px, unter den empfohlenen 3000\u00a0\u00d7\u00a03000\u00a0px.\",\"b_cover_ok\":\"Quadratisch und mindestens 3000\u00a0\u00d7\u00a03000\u00a0px, wie Apple es empfiehlt.\",\"knopf_kopieren\":\"Ergebnis kopieren\",\"kopiert\":\"kopiert\",\"kopieren_fehler\":\"Kopieren nicht m\u00f6glich\",\"fehler_format\":\"Diese Datei geh\u00f6rt zu keinem der hier gelesenen Formate: WAV, RF64, AIFF, FLAC, MP3, M4A, Ogg Vorbis oder Opus.\",\"fehler_lesen\":\"Die Datei lie\u00df sich nicht lesen.\",\"h_erklaerung\":\"Was gepr\u00fcft wird und warum\",\"erkl_format\":\"Apple Music nimmt Ton mit 44,1, 48, 88,2, 96, 176,4 oder 192\u00a0kHz bei 16 oder 24\u00a0Bit und bittet um den Master in der h\u00f6chsten verf\u00fcgbaren Aufl\u00f6sung. Eine verlustbehaftete Datei erf\u00fcllt das nicht: Der Encoder hat Teile des Signals schon verworfen, und der Dienst kodiert noch einmal.\",\"erkl_bits\":\"Genutzte Bits: F\u00fcr jeden Wert werden die untersten Bits gepr\u00fcft. Sind sie in der ganzen Datei null, tr\u00e4gt die zus\u00e4tzliche Tiefe nichts, etwa bei einem 16-Bit-Master, der als 24\u00a0Bit gespeichert wurde. Apple Digital Masters schlie\u00dft dieses Auff\u00fcllen ausdr\u00fccklich aus. In Gleitkommadateien fragt die Pr\u00fcfung, ob jeder Wert auf dem 16- oder dem 24-Bit-Raster liegt.\",\"erkl_spitzen\":\"Vollaussteuerung ist der h\u00f6chste Ganzzahlwert; drei oder mehr solche Werte hintereinander z\u00e4hlen als geclippte Stelle. Der True Peak folgt ITU-R BS.1770 mit dem Filter aus 48 Koeffizienten bei vierfacher \u00dcberabtastung. Er findet Spitzen zwischen den Abtastwerten, die eine Wandlung oder ein Encoder zu echten macht.\",\"erkl_stille\":\"Stille hei\u00dft hier unter \u221260\u00a0dBFS. Die Grenzen von einer Sekunde am Anfang, f\u00fcnf Sekunden am Ende, \u221240\u00a0dBFS f\u00fcr den ersten und den letzten Wert und \u221260\u00a0dBFS f\u00fcr den Gleichanteil sind Regeln dieser Pr\u00fcfung, keine Vorgaben eines Dienstes. Diese Grenzen markieren, was vor dem Hochladen ein Anh\u00f6ren lohnt.\",\"erkl_tags\":\"Gelesen werden ID3v2 und ID3v1, Vorbis-Kommentare in FLAC, Ogg und Opus, RIFF INFO und ID3-Chunks in WAV und AIFF sowie die MP4-Metadaten. Beim ISRC entscheidet das Feld: TSRC in ID3, ISRC in Vorbis-Kommentaren. ffmpeg schreibt bei -metadata ISRC=\u2026 andere Felder, wie der Artikel zu Release-Metadaten gemessen hat.\",\"erkl_cover\":\"Apple empfiehlt 3000\u00a0\u00d7\u00a03000\u00a0Pixel oder mehr, verlangt mindestens 1400\u00a0\u00d7\u00a01400 und ein quadratisches Bild als JPEG oder PNG. Gepr\u00fcft wird das eingebettete Bild; das Cover f\u00fcr den Vertrieb ist eine eigene Datei.\",\"quellen_titel\":\"Quellen\",\"grenze\":\"Die genannten Anforderungen sind die von Apple; andere Vertriebe ver\u00f6ffentlichen eigene. Formate au\u00dfer WAV und AIFF h\u00e4ngen am Decoder des Browsers, der in manchen Browsern ALAC oder komprimiertes AIFC nicht liest. Die Lautheit misst das LUFS-Messger\u00e4t.\"};<\/p>\n<p>    \/\/ KERN-ANFANG ------------------------------------------------------------\n    \/\/ Leser und Messung ohne Dokument: derselbe Text laeuft im Browser und in Node.<\/p>\n<p>    \/\/ Apple Music Provider Support, \"Digital packaging for music\": zulaessige Raten.\n    var RATEN_APPLE = [44100, 48000, 88200, 96000, 176400, 192000];\n    var STILLE = Math.pow(10, -60 \/ 20);          \/\/ Grenze fuer Stille: -60 dBFS\n    var SPRUNG = Math.pow(10, -40 \/ 20);          \/\/ erster\/letzter Wert ab -40 dBFS gilt als Sprung\n    var DC_GRENZE = Math.pow(10, -60 \/ 20);       \/\/ Gleichanteil ab -60 dBFS wird gemeldet\n    var STILLE_ANFANG_S = 1, STILLE_ENDE_S = 5;   \/\/ Hinweisgrenzen in Sekunden\n    var COVER_EMPFOHLEN = 3000, COVER_MINDEST = 1400;<\/p>\n<p>    \/\/ ITU-R BS.1770-5, Anhang 2: 4-fach ueberabtastendes FIR, vier Phasen zu je zwoelf Werten.\n    var TP_PHASEN = [\n        [0.0017089843750, 0.0109863281250, -0.0196533203125, 0.0332031250000, -0.0594482421875, 0.1373291015625,\n         0.9721679687500, -0.1022949218750, 0.0476074218750, -0.0266113281250, 0.0148925781250, -0.0083007812500],\n        [-0.0291748046875, 0.0292968750000, -0.0517578125000, 0.0891113281250, -0.1665039062500, 0.4650878906250,\n         0.7797851562500, -0.2003173828125, 0.1015625000000, -0.0582275390625, 0.0330810546875, -0.0189208984375],\n        [-0.0189208984375, 0.0330810546875, -0.0582275390625, 0.1015625000000, -0.2003173828125, 0.7797851562500,\n         0.4650878906250, -0.1665039062500, 0.0891113281250, -0.0517578125000, 0.0292968750000, -0.0291748046875],\n        [-0.0083007812500, 0.0148925781250, -0.0266113281250, 0.0476074218750, -0.1022949218750, 0.9721679687500,\n         0.1373291015625, -0.0594482421875, 0.0332031250000, -0.0196533203125, 0.0109863281250, 0.0017089843750]\n    ];<\/p>\n<p>    \/\/ ---- Bytes --------------------------------------------------------------\n    function str(u8, o, l) {\n        var s = '';\n        for (var i = 0; i < l &#038;&#038; o + i < u8.length; i++) { s += String.fromCharCode(u8[o + i]); }\n        return s;\n    }\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    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 syncsafe(u8, o) {\n        return ((u8[o] & 0x7F) << 21) | ((u8[o + 1] &#038; 0x7F) << 14) | ((u8[o + 2] &#038; 0x7F) << 7) | (u8[o + 3] &#038; 0x7F);\n    }\n\n    function utf8(u8) {\n        if (typeof TextDecoder !== 'undefined') { return new TextDecoder('utf-8').decode(u8); }\n        var s = str(u8, 0, u8.length);\n        try { return decodeURIComponent(escape(s)); } catch (e) { return s; }\n    }\n    \/\/ art wie im ID3-Kodierungsbyte: 0 Latin-1, 1 UTF-16 mit BOM, 2 UTF-16BE, 3 UTF-8\n    function text(u8, art) {\n        var s = '', i;\n        if (art === 3) { s = utf8(u8); }\n        else if (art === 1 || art === 2) {\n            var gross = art === 2;\n            i = 0;\n            if (u8.length >= 2 && u8[0] === 0xFF && u8[1] === 0xFE) { gross = false; i = 2; }\n            else if (u8.length >= 2 && u8[0] === 0xFE && u8[1] === 0xFF) { gross = true; i = 2; }\n            for (; i + 1 < u8.length; i += 2) {\n                s += String.fromCharCode(gross ? (u8[i] << 8) | u8[i + 1] : u8[i] | (u8[i + 1] << 8));\n            }\n        } else { s = str(u8, 0, u8.length); }\n        \/\/ ID3v2.4 trennt mehrere Werte mit Nullzeichen; der erste zaehlt.\n        var teile = s.split('\\u0000');\n        for (i = 0; i < teile.length; i++) { if (teile[i].trim() !== '') { return teile[i].trim(); } }\n        return '';\n    }\n    function nullStelle(u8, p, breit) {\n        if (breit) {\n            for (var i = p; i + 1 < u8.length; i += 2) { if (u8[i] === 0 &#038;&#038; u8[i + 1] === 0) { return i; } }\n            return u8.length;\n        }\n        for (var j = p; j < u8.length; j++) { if (u8[j] === 0) { return j; } }\n        return u8.length;\n    }\n    function base64(s) {\n        s = s.replace(\/[^A-Za-z0-9+\\\/=]\/g, '');\n        var roh = typeof atob === 'function' ? atob(s) : Buffer.from(s, 'base64').toString('binary');\n        var u8 = new Uint8Array(roh.length);\n        for (var i = 0; i < roh.length; i++) { u8[i] = roh.charCodeAt(i); }\n        return u8;\n    }\n\n    \/\/ ---- Bilder -------------------------------------------------------------\n    function bildMasse(u8) {\n        if (u8.length >= 24 && u8[0] === 0x89 && u8[1] === 0x50 && u8[2] === 0x4E && u8[3] === 0x47) {\n            return { typ: 'PNG', breite: be32(u8, 16), hoehe: be32(u8, 20) };\n        }\n        if (u8.length >= 4 && u8[0] === 0xFF && u8[1] === 0xD8) {\n            var p = 2;\n            while (p + 9 < u8.length) {\n                if (u8[p] !== 0xFF) { p++; continue; }\n                var m = u8[p + 1];\n                if (m === 0xFF) { p++; continue; }\n                if (m === 0xD8 || m === 0x01 || (m >= 0xD0 && m <= 0xD7)) { p += 2; continue; }\n                if (m >= 0xC0 && m <= 0xCF &#038;&#038; m !== 0xC4 &#038;&#038; m !== 0xC8 &#038;&#038; m !== 0xCC) {\n                    return { typ: 'JPEG', hoehe: be16(u8, p + 5), breite: be16(u8, p + 7) };\n                }\n                if (m === 0xDA) { break; }\n                p += 2 + be16(u8, p + 2);\n            }\n            return { typ: 'JPEG', breite: null, hoehe: null };\n        }\n        if (u8.length >= 2 && u8[0] === 0x42 && u8[1] === 0x4D) { return { typ: 'BMP', breite: null, hoehe: null }; }\n        if (u8.length >= 3 && u8[0] === 0x47 && u8[1] === 0x49 && u8[2] === 0x46) { return { typ: 'GIF', breite: le16(u8, 6), hoehe: le16(u8, 8) }; }\n        return { typ: null, breite: null, hoehe: null };\n    }\n    function bildEintrag(daten, ort, bildtyp, breite, hoehe) {\n        var m = bildMasse(daten);\n        return { ort: ort, bildtyp: bildtyp === undefined ? null : bildtyp, typ: m.typ,\n                 breite: m.breite || breite || null, hoehe: m.hoehe || hoehe || null, bytes: daten.length };\n    }<\/p>\n<p>    function neueTags() { return { titel: [], kuenstler: [], isrc: [], cover: [] }; }<\/p>\n<p>    \/\/ ---- ID3v2 und ID3v1 ----------------------------------------------------\n    function entSync(u8) {\n        var raus = new Uint8Array(u8.length), n = 0;\n        for (var i = 0; i < u8.length; i++) {\n            raus[n++] = u8[i];\n            if (u8[i] === 0xFF &#038;&#038; u8[i + 1] === 0x00) { i++; }\n        }\n        return raus.subarray(0, n);\n    }\n\n    function id3Rahmen(id, b, tags) {\n        if (!b.length) { return; }\n        var art = b[0], breit = art === 1 || art === 2, e;\n        if (id === 'TIT2' || id === 'TT2') { tags.titel.push({ wert: text(b.subarray(1), art), ort: 'id3' }); }\n        else if (id === 'TPE1' || id === 'TP1') { tags.kuenstler.push({ wert: text(b.subarray(1), art), ort: 'id3' }); }\n        else if (id === 'TSRC' || id === 'TRC') { tags.isrc.push({ wert: text(b.subarray(1), art), ort: 'tsrc' }); }\n        else if (id === 'TXXX' || id === 'TXX') {\n            e = nullStelle(b, 1, breit);\n            var beschreibung = text(b.subarray(1, e), art);\n            if (\/^isrc$\/i.test(beschreibung)) {\n                tags.isrc.push({ wert: text(b.subarray(e + (breit ? 2 : 1)), art), ort: 'txxx' });\n            }\n        } else if (id === 'APIC') {\n            var m = nullStelle(b, 1, false);\n            var bildtyp = b[m + 1];\n            e = nullStelle(b, m + 2, breit);\n            tags.cover.push(bildEintrag(b.subarray(e + (breit ? 2 : 1)), 'id3', bildtyp));\n        } else if (id === 'PIC') {\n            e = nullStelle(b, 5, breit);\n            tags.cover.push(bildEintrag(b.subarray(e + (breit ? 2 : 1)), 'id3', b[4]));\n        }\n    }\n\n    \/\/ Gibt die Laenge des Tags zurueck, 0 wenn an o keiner beginnt.\n    function id3Lesen(u8, o, tags) {\n        if (o + 10 > u8.length || u8[o] !== 0x49 || u8[o + 1] !== 0x44 || u8[o + 2] !== 0x33) { return 0; }\n        var ver = u8[o + 3], flaggen = u8[o + 5], groesse = syncsafe(u8, o + 6);\n        if (ver < 2 || ver > 4) { return 0; }\n        var d = u8.subarray(o + 10, Math.min(u8.length, o + 10 + groesse));\n        if ((flaggen & 0x80) && ver < 4) { d = entSync(d); }\n        var p = 0;\n        if ((flaggen &#038; 0x40) &#038;&#038; ver >= 3) { p += ver === 4 ? syncsafe(d, 0) : be32(d, 0) + 4; }\n        var kopf = ver === 2 ? 6 : 10;\n        while (p + kopf <= d.length) {\n            var id, fg;\n            if (ver === 2) { id = str(d, p, 3); fg = (d[p + 3] << 16) | (d[p + 4] << 8) | d[p + 5]; }\n            else { id = str(d, p, 4); fg = ver === 4 ? syncsafe(d, p + 4) : be32(d, p + 4); }\n            if (!\/^[A-Z0-9]{3,4}$\/.test(id) || fg <= 0 || p + kopf + fg > d.length) { break; }\n            var format = ver >= 3 ? d[p + 9] : 0;\n            var inhalt = d.subarray(p + kopf, p + kopf + fg);\n            var gesperrt = ver === 4 ? (format & 0x0C) : (ver === 3 ? (format & 0xC0) : 0);\n            if (ver === 4 && (format & 0x02)) { inhalt = entSync(inhalt); }\n            if (ver === 4 && (format & 0x01)) { inhalt = inhalt.subarray(4); }\n            if (!gesperrt) { id3Rahmen(id, inhalt, tags); }\n            p += kopf + fg;\n        }\n        return 10 + groesse + (flaggen & 0x10 ? 10 : 0);\n    }<\/p>\n<p>    function id3v1Lesen(u8, tags) {\n        if (u8.length < 128) { return; }\n        var o = u8.length - 128;\n        if (str(u8, o, 3) !== 'TAG') { return; }\n        var titel = text(u8.subarray(o + 3, o + 33), 0), kuenstler = text(u8.subarray(o + 33, o + 63), 0);\n        if (titel) { tags.titel.push({ wert: titel, ort: 'id3v1' }); }\n        if (kuenstler) { tags.kuenstler.push({ wert: kuenstler, ort: 'id3v1' }); }\n    }\n\n    \/\/ ---- Vorbis-Kommentar und FLAC-Bild -------------------------------------\n    function flacBild(u8, p, ende, tags, ort) {\n        if (p + 32 > ende) { return; }\n        var bildtyp = be32(u8, p), ml = be32(u8, p + 4);\n        var q = p + 8 + ml, bl = be32(u8, q);\n        q += 4 + bl;\n        var breite = be32(u8, q), hoehe = be32(u8, q + 4), dl = be32(u8, q + 16);\n        var daten = u8.subarray(q + 20, Math.min(ende, q + 20 + dl));\n        tags.cover.push(bildEintrag(daten, ort, bildtyp, breite, hoehe));\n    }<\/p>\n<p>    function vorbisKommentar(u8, p, ende, tags) {\n        if (p + 8 > ende) { return; }\n        p += 4 + le32(u8, p);\n        var anzahl = le32(u8, p);\n        p += 4;\n        for (var k = 0; k < anzahl &#038;&#038; p + 4 <= ende; k++) {\n            var l = le32(u8, p);\n            if (p + 4 + l > ende) { break; }\n            var eintrag = u8.subarray(p + 4, p + 4 + l);\n            p += 4 + l;\n            var gleich = -1;\n            for (var i = 0; i < eintrag.length &#038;&#038; i < 64; i++) { if (eintrag[i] === 0x3D) { gleich = i; break; } }\n            if (gleich < 1) { continue; }\n            var name = str(eintrag, 0, gleich).toUpperCase();\n            if (name === 'METADATA_BLOCK_PICTURE') {\n                var bild = base64(str(eintrag, gleich + 1, eintrag.length - gleich - 1));\n                flacBild(bild, 0, bild.length, tags, 'vorbis_bild');\n            } else if (name === 'COVERART') {\n                tags.cover.push(bildEintrag(base64(str(eintrag, gleich + 1, eintrag.length - gleich - 1)), 'vorbis_bild', 3));\n            } else if (name === 'TITLE' || name === 'ARTIST' || name === 'ISRC') {\n                var wert = utf8(eintrag.subarray(gleich + 1)).trim();\n                if (name === 'TITLE') { tags.titel.push({ wert: wert, ort: 'vorbis' }); }\n                else if (name === 'ARTIST') { tags.kuenstler.push({ wert: wert, ort: 'vorbis' }); }\n                else { tags.isrc.push({ wert: wert, ort: 'vorbis' }); }\n            }\n        }\n    }\n\n    \/\/ ---- WAV, RF64, AIFF: Kopf, Tags und Abtastwerte ------------------------\n    \/\/ Liest die Werte selbst, damit nichts umgerechnet wird, und haelt dabei fest,\n    \/\/ welche Bits ueberhaupt vorkommen (Bit-Padding) und ob Gleitkommawerte genau\n    \/\/ auf ein 16- oder 24-Bit-Raster fallen.\n    function pcmLesen(puffer, start, laenge, anzahl, bytes, art, klein) {\n        var rahmen = Math.floor(laenge \/ (bytes * anzahl)), raus = [], c, i, k, v, s;\n        for (c = 0; c < anzahl; c++) { raus.push(new Float32Array(rahmen)); }\n        var oder = 0, alle16 = true, alle24 = true, n = rahmen * anzahl;\n        if (art === 'float') {\n            var dvf = new DataView(puffer, start, n * bytes);\n            for (i = 0, k = 0; i < rahmen; i++) {\n                for (c = 0; c < anzahl; c++, k++) {\n                    v = bytes === 4 ? dvf.getFloat32(k * 4, klein) : dvf.getFloat64(k * 8, klein);\n                    raus[c][i] = v;\n                    if (alle24) {\n                        s = v * 8388608;\n                        if (s !== Math.floor(s)) { alle24 = false; alle16 = false; }\n                        else if (alle16) { s = v * 32768; if (s !== Math.floor(s)) { alle16 = false; } }\n                    }\n                }\n            }\n            return { kanaele: raus, oder: null, alle16: alle16, alle24: alle24 };\n        }\n        var teiler = Math.pow(2, bytes * 8 - 1);\n        if (klein &#038;&#038; (bytes === 2 || bytes === 4)) {\n            var stueck = puffer.slice(start, start + n * bytes);\n            var a = bytes === 2 ? new Int16Array(stueck) : new Int32Array(stueck);\n            for (i = 0, k = 0; i < rahmen; i++) {\n                for (c = 0; c < anzahl; c++, k++) { v = a[k]; oder |= v; raus[c][i] = v \/ teiler; }\n            }\n            return { kanaele: raus, oder: oder, alle16: null, alle24: null };\n        }\n        var u8 = new Uint8Array(puffer, start, n * bytes), dv = new DataView(puffer, start, n * bytes), o = 0;\n        for (i = 0; i < rahmen; i++) {\n            for (c = 0; c < anzahl; c++) {\n                if (bytes === 1) { v = klein ? u8[o] - 128 : dv.getInt8(o); }\n                else if (bytes === 2) { v = dv.getInt16(o, klein); }\n                else if (bytes === 3) {\n                    v = klein ? (u8[o] | (u8[o + 1] << 8) | (u8[o + 2] << 16)) : ((u8[o] << 16) | (u8[o + 1] << 8) | u8[o + 2]);\n                    if (v &#038; 0x800000) { v -= 0x1000000; }\n                } else { v = dv.getInt32(o, klein); }\n                oder |= v;\n                raus[c][i] = v \/ teiler;\n                o += bytes;\n            }\n        }\n        return { kanaele: raus, oder: oder, alle16: null, alle24: null };\n    }\n\n    function riffInfo(u8, p, ende, tags) {\n        while (p + 8 <= ende) {\n            var id = str(u8, p, 4), l = le32(u8, p + 4);\n            var wert = text(u8.subarray(p + 8, Math.min(ende, p + 8 + l)), 3);\n            if (id === 'INAM') { tags.titel.push({ wert: wert, ort: 'riff' }); }\n            else if (id === 'IART') { tags.kuenstler.push({ wert: wert, ort: 'riff' }); }\n            else if (id === 'ISRC') { tags.isrc.push({ wert: wert, ort: 'riff_isrc' }); }\n            p += 8 + l + (l &#038; 1);\n        }\n    }\n\n    function wavLesen(puffer, info) {\n        var u8 = new Uint8Array(puffer), n = u8.length, p = 12, fmt = null, ds64 = null, daten = null;\n        while (p + 8 <= n) {\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 === 'data' && l === 0xFFFFFFFF && ds64 !== null) { l = ds64; }\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                daten = { start: p + 8, laenge: Math.min(l, n - p - 8) };\n            } else if (id === 'LIST' && str(u8, p + 8, 4) === 'INFO') {\n                riffInfo(u8, p + 12, Math.min(n, p + 8 + l), info.tags);\n            } else if (id === 'id3 ' || id === 'ID3 ') {\n                id3Lesen(u8, p + 8, info.tags);\n            }\n            if (l === 0xFFFFFFFF) { break; }\n            p += 8 + l + (l & 1);\n        }\n        if (!fmt) { info.fehler = 'fmt'; return info; }\n        info.rate = fmt.rate;\n        info.kanaeleAnzahl = fmt.anzahl;\n        info.bits = fmt.bits;\n        info.gleitkomma = fmt.tag === 3;\n        info.verlustfrei = fmt.tag === 1 || fmt.tag === 3;\n        info.ganzzahl = fmt.tag === 1;\n        var bytes = fmt.bits \/ 8;\n        if (!daten || !info.verlustfrei || !fmt.anzahl || (fmt.tag === 1 && [1, 2, 3, 4].indexOf(bytes) === -1) ||\n            (fmt.tag === 3 && bytes !== 4 && bytes !== 8)) {\n            info.fehler = daten ? 'codec' : 'data';\n            return info;\n        }\n        var w = pcmLesen(puffer, daten.start, daten.laenge, fmt.anzahl, bytes, fmt.tag === 3 ? 'float' : 'int', true);\n        info.kanaele = w.kanaele;\n        info.oder = w.oder; info.alle16 = w.alle16; info.alle24 = w.alle24;\n        return info;\n    }<\/p>\n<p>    function erweitert80(u8, o) {\n        var exp = be16(u8, o) & 0x7FFF, hi = be32(u8, o + 2), lo = be32(u8, o + 6);\n        if (!exp && !hi && !lo) { return 0; }\n        return (hi * 4294967296 + lo) * Math.pow(2, exp - 16383 - 63);\n    }<\/p>\n<p>    function aiffLesen(puffer, info, aifc) {\n        var u8 = new Uint8Array(puffer), n = u8.length, p = 12, comm = null, ssnd = null;\n        while (p + 8 <= n) {\n            var id = str(u8, p, 4), l = be32(u8, p + 4);\n            if (id === 'COMM') {\n                comm = { anzahl: be16(u8, p + 8), bits: be16(u8, p + 14), rate: Math.round(erweitert80(u8, p + 16)), art: 'NONE' };\n                if (aifc &#038;&#038; l >= 22) { comm.art = str(u8, p + 26, 4); }\n            } else if (id === 'SSND') {\n                var versatz = be32(u8, p + 8);\n                ssnd = { start: p + 16 + versatz, laenge: Math.min(l - 8 - versatz, n - p - 16 - versatz) };\n            } else if (id === 'NAME') { info.tags.titel.push({ wert: text(u8.subarray(p + 8, p + 8 + l), 0), ort: 'aiff' }); }\n            else if (id === 'AUTH') { info.tags.kuenstler.push({ wert: text(u8.subarray(p + 8, p + 8 + l), 0), ort: 'aiff' }); }\n            else if (id === 'ID3 ' || id === 'id3 ') { id3Lesen(u8, p + 8, info.tags); }\n            p += 8 + l + (l & 1);\n        }\n        if (!comm) { info.fehler = 'COMM'; return info; }\n        info.rate = comm.rate;\n        info.kanaeleAnzahl = comm.anzahl;\n        var art = comm.art, gleit = \/^(fl32|FL32|fl64|FL64)$\/.test(art);\n        info.bits = gleit ? (art.slice(2) === '32' ? 32 : 64) : comm.bits;\n        info.gleitkomma = gleit;\n        info.ganzzahl = art === 'NONE' || art === 'twos' || art === 'sowt';\n        info.verlustfrei = info.ganzzahl || gleit;\n        if (!info.verlustfrei) { info.format = 'AIFC (' + art.trim() + ')'; info.verlustfrei = null; info.fehler = 'codec'; return info; }\n        if (!ssnd) { info.fehler = 'SSND'; return info; }\n        var bytes = gleit ? info.bits \/ 8 : Math.ceil(comm.bits \/ 8);\n        var w = pcmLesen(puffer, ssnd.start, ssnd.laenge, comm.anzahl, bytes, gleit ? 'float' : 'int', art === 'sowt');\n        info.kanaele = w.kanaele;\n        \/\/ Bei weniger als voller Byte-Breite (etwa 20 Bit) sind die unteren Bits laut Norm leer.\n        info.oder = w.oder === null ? null : w.oder >> (bytes * 8 - comm.bits);\n        info.alle16 = w.alle16; info.alle24 = w.alle24;\n        return info;\n    }<\/p>\n<p>    \/\/ ---- FLAC ---------------------------------------------------------------\n    function flacLesen(u8, o, info) {\n        var p = o + 4, letzter = false;\n        info.format = 'FLAC';\n        info.verlustfrei = true;\n        info.ganzzahl = true;\n        while (!letzter && p + 4 <= u8.length) {\n            var kopf = u8[p], typ = kopf &#038; 0x7F, l = (u8[p + 1] << 16) | (u8[p + 2] << 8) | u8[p + 3];\n            letzter = (kopf &#038; 0x80) !== 0;\n            var d = p + 4, ende = Math.min(u8.length, d + l);\n            if (typ === 0 &#038;&#038; l >= 18) {\n                info.rate = (u8[d + 10] << 12) | (u8[d + 11] << 4) | (u8[d + 12] >> 4);\n                info.kanaeleAnzahl = ((u8[d + 12] >> 1) & 7) + 1;\n                info.bits = (((u8[d + 12] & 1) << 4) | (u8[d + 13] >> 4)) + 1;\n                info.abtastwerte = (u8[d + 13] & 0x0F) * 4294967296 + be32(u8, d + 14);\n            } else if (typ === 4) { vorbisKommentar(u8, d, ende, info.tags); }\n            else if (typ === 6) { flacBild(u8, d, ende, info.tags, 'flac_bild'); }\n            p = ende;\n        }\n        return info;\n    }<\/p>\n<p>    \/\/ ---- Ogg ----------------------------------------------------------------\n    function oggPakete(u8, hoechstens) {\n        var pakete = [], teile = [], p = 0;\n        function verbinden() {\n            var l = 0, i;\n            for (i = 0; i < teile.length; i++) { l += teile[i].length; }\n            var r = new Uint8Array(l), o = 0;\n            for (i = 0; i < teile.length; i++) { r.set(teile[i], o); o += teile[i].length; }\n            teile = [];\n            return r;\n        }\n        while (p + 27 <= u8.length &#038;&#038; pakete.length < hoechstens) {\n            if (str(u8, p, 4) !== 'OggS') { break; }\n            var segmente = u8[p + 26], q = p + 27 + segmente;\n            for (var s = 0; s < segmente &#038;&#038; pakete.length < hoechstens; s++) {\n                var l = u8[p + 27 + s];\n                teile.push(u8.subarray(q, Math.min(u8.length, q + l)));\n                q += l;\n                if (l < 255) { pakete.push(verbinden()); }\n            }\n            p = q;\n        }\n        return pakete;\n    }\n\n    function oggLesen(u8, info) {\n        var pakete = oggPakete(u8, 6);\n        if (!pakete.length) { info.fehler = 'ogg'; return info; }\n        var erst = pakete[0];\n        if (erst[0] === 1 &#038;&#038; str(erst, 1, 6) === 'vorbis') {\n            info.format = 'Ogg Vorbis'; info.verlustfrei = false;\n            info.kanaeleAnzahl = erst[11]; info.rate = le32(erst, 12);\n            if (pakete[1] &#038;&#038; pakete[1][0] === 3 &#038;&#038; str(pakete[1], 1, 6) === 'vorbis') {\n                vorbisKommentar(pakete[1], 7, pakete[1].length, info.tags);\n            }\n        } else if (str(erst, 0, 8) === 'OpusHead') {\n            info.format = 'Opus'; info.verlustfrei = false;\n            info.kanaeleAnzahl = erst[9]; info.rate = 48000;\n            if (pakete[1] &#038;&#038; str(pakete[1], 0, 8) === 'OpusTags') {\n                vorbisKommentar(pakete[1], 8, pakete[1].length, info.tags);\n            }\n        } else if (erst[0] === 0x7F &#038;&#038; str(erst, 1, 4) === 'FLAC' &#038;&#038; str(erst, 9, 4) === 'fLaC') {\n            var s = 17;\n            info.format = 'Ogg FLAC'; info.verlustfrei = true; info.ganzzahl = true;\n            info.rate = (erst[s + 10] << 12) | (erst[s + 11] << 4) | (erst[s + 12] >> 4);\n            info.kanaeleAnzahl = ((erst[s + 12] >> 1) & 7) + 1;\n            info.bits = (((erst[s + 12] & 1) << 4) | (erst[s + 13] >> 4)) + 1;\n            for (var i = 1; i < pakete.length; i++) {\n                var t = pakete[i][0] &#038; 0x7F, l = (pakete[i][1] << 16) | (pakete[i][2] << 8) | pakete[i][3];\n                if (t === 4) { vorbisKommentar(pakete[i], 4, Math.min(pakete[i].length, 4 + l), info.tags); }\n                else if (t === 6) { flacBild(pakete[i], 4, Math.min(pakete[i].length, 4 + l), info.tags, 'flac_bild'); }\n            }\n        } else { info.fehler = 'ogg'; }\n        return info;\n    }\n\n    \/\/ ---- MP4 \/ M4A ----------------------------------------------------------\n    function mp4Lesen(u8, info) {\n        var schluessel = null;\n        info.format = 'MP4';\n        function eintrag(name, von, bis) {\n            var werte = [], frei = null, p = von;\n            while (p + 8 <= bis) {\n                var g = be32(u8, p), n = str(u8, p + 4, 4);\n                if (g < 8 || p + g > bis) { break; }\n                if (n === 'name') { frei = str(u8, p + 12, g - 12); }\n                else if (n === 'data') { werte.push({ typ: be32(u8, p + 8) & 0xFFFFFF, daten: u8.subarray(p + 16, p + g) }); }\n                p += g;\n            }\n            var schl = name;\n            if (name === '----' && frei) { schl = '----:' + frei; }\n            werte.forEach(function (w) {\n                if (schl === '\u00a9nam' || \/^(title|com\\.apple\\.quicktime\\.title)$\/i.test(schl)) {\n                    info.tags.titel.push({ wert: utf8(w.daten).trim(), ort: schl.length === 4 ? 'mp4' : 'mdta' });\n                } else if (schl === '\u00a9ART' || \/^(artist|com\\.apple\\.quicktime\\.artist)$\/i.test(schl)) {\n                    info.tags.kuenstler.push({ wert: utf8(w.daten).trim(), ort: schl.length === 4 ? 'mp4' : 'mdta' });\n                } else if (schl === 'covr' || \/artwork$\/i.test(schl)) {\n                    info.tags.cover.push(bildEintrag(w.daten, 'mp4', 3));\n                } else if (\/^----:isrc$\/i.test(schl)) {\n                    info.tags.isrc.push({ wert: utf8(w.daten).trim(), ort: 'mp4_frei' });\n                } else if (\/(^|\\.)isrc$\/i.test(schl)) {\n                    info.tags.isrc.push({ wert: utf8(w.daten).trim(), ort: 'mdta' });\n                }\n            });\n        }\n        function ilst(von, bis) {\n            var p = von;\n            while (p + 8 <= bis) {\n                var g = be32(u8, p);\n                if (g < 8 || p + g > bis) { break; }\n                var name = str(u8, p + 4, 4);\n                if (u8[p + 4] === 0 && u8[p + 5] === 0 && schluessel) {\n                    var nr = be32(u8, p + 4);\n                    name = schluessel[nr - 1] || name;\n                }\n                eintrag(name, p + 8, p + g);\n                p += g;\n            }\n        }\n        function kaesten(von, bis, tiefe) {\n            var p = von;\n            while (p + 8 <= bis &#038;&#038; tiefe < 12) {\n                var g = be32(u8, p), name = str(u8, p + 4, 4), innen = p + 8;\n                if (g === 1) { g = be32(u8, p + 8) * 4294967296 + be32(u8, p + 12); innen = p + 16; }\n                if (g === 0) { g = bis - p; }\n                if (g < 8 || p + g > bis) { break; }\n                var ende = p + g;\n                if (\/^(moov|trak|mdia|minf|stbl|udta)$\/.test(name)) { kaesten(innen, ende, tiefe + 1); }\n                else if (name === 'meta') {\n                    \/\/ iTunes: volle Box mit vier Bytes Version; QuickTime: ohne.\n                    kaesten(str(u8, innen + 4, 4) === 'hdlr' ? innen : innen + 4, ende, tiefe + 1);\n                } else if (name === 'mdhd') {\n                    var v = u8[innen];\n                    info.rate = v === 1 ? be32(u8, innen + 20) : be32(u8, innen + 12);\n                } else if (name === 'stsd' && !info.codec) {\n                    var e = innen + 8, c = e + 8;\n                    info.codec = str(u8, e + 4, 4);\n                    info.kanaeleAnzahl = be16(u8, c + 16);\n                    var tiefeBits = be16(u8, c + 18);\n                    if (info.codec === 'alac') {\n                        var innenAlac = c + 28;\n                        if (str(u8, innenAlac + 4, 4) === 'alac') { tiefeBits = u8[innenAlac + 17] || tiefeBits; }\n                        info.bits = tiefeBits;\n                    } else if (info.codec === 'fLaC') { info.bits = tiefeBits; }\n                } else if (name === 'keys') {\n                    var anzahl = be32(u8, innen + 4), q = innen + 8;\n                    schluessel = [];\n                    for (var k = 0; k < anzahl &#038;&#038; q + 8 <= ende; k++) {\n                        var kl = be32(u8, q);\n                        if (kl < 8) { break; }\n                        schluessel.push(str(u8, q + 8, kl - 8));\n                        q += kl;\n                    }\n                } else if (name === 'ilst') { ilst(innen, ende); }\n                p = ende;\n            }\n        }\n        kaesten(0, u8.length, 0);\n        if (info.codec === 'alac' || info.codec === 'fLaC') { info.verlustfrei = true; info.ganzzahl = true; info.format = info.codec === 'alac' ? 'ALAC (MP4)' : 'FLAC (MP4)'; }\n        else if (info.codec === 'mp4a' || info.codec === 'Opus' || info.codec === '.mp3') { info.verlustfrei = false; info.format = info.codec === 'mp4a' ? 'AAC (MP4)' : info.codec + ' (MP4)'; }\n        else { info.verlustfrei = null; }\n        return info;\n    }\n\n    \/\/ ---- MP3 und AAC (ADTS) -------------------------------------------------\n    function mpegLesen(u8, info) {\n        var start = 0, l;\n        while ((l = id3Lesen(u8, start, info.tags)) > 0) { start += l; }\n        id3v1Lesen(u8, info.tags);\n        var bis = Math.min(u8.length - 4, start + 65536);\n        for (var j = start; j < bis; 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;\n            if (schicht === 0 && (u8[j + 1] & 0xF6) === 0xF0) {\n                var idx = (u8[j + 2] >> 2) & 15;\n                var raten = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];\n                if (idx >= raten.length) { continue; }\n                info.format = 'AAC (ADTS)'; info.rate = raten[idx]; info.verlustfrei = false;\n                info.kanaeleAnzahl = ((u8[j + 2] & 1) << 2) | (u8[j + 3] >> 6);\n                return info;\n            }\n            var 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            info.format = schicht === 1 ? 'MP3' : 'MPEG Audio';\n            info.rate = version === 3 ? basis : (version === 2 ? basis \/ 2 : basis \/ 4);\n            info.kanaeleAnzahl = (u8[j + 3] >> 6) === 3 ? 1 : 2;\n            info.verlustfrei = false;\n            return info;\n        }\n        info.fehler = 'format';\n        return info;\n    }<\/p>\n<p>    \/\/ Liest Kopf, Tags und - bei WAV und AIFF - die Abtastwerte.\n    function lesen(puffer) {\n        var u8 = new Uint8Array(puffer);\n        var info = { format: null, verlustfrei: null, ganzzahl: false, gleitkomma: false, rate: null, bits: null,\n                     kanaeleAnzahl: null, kanaele: null, oder: null, alle16: null, alle24: null,\n                     tags: neueTags(), fehler: null, codec: null };\n        if (u8.length < 16) { info.fehler = 'format'; return info; }\n        var k4 = str(u8, 0, 4), art = str(u8, 8, 4);\n        if ((k4 === 'RIFF' || k4 === 'RF64' || k4 === 'BW64') &#038;&#038; art === 'WAVE') { info.format = k4 === 'RIFF' ? 'WAV' : k4; return wavLesen(puffer, info); }\n        if (k4 === 'FORM' &#038;&#038; (art === 'AIFF' || art === 'AIFC')) { info.format = art; return aiffLesen(puffer, info, art === 'AIFC'); }\n        if (k4 === 'OggS') { return oggLesen(u8, info); }\n        if (str(u8, 4, 4) === 'ftyp') { return mp4Lesen(u8, info); }\n        var o = 0, l;\n        while ((l = id3Lesen(u8, o, info.tags)) > 0) { o += l; }\n        if (str(u8, o, 4) === 'fLaC') { return flacLesen(u8, o, info); }\n        info.tags = neueTags();\n        return mpegLesen(u8, info);\n    }<\/p>\n<p>    \/\/ Bei dekodierten FLAC-Dateien: stehen alle Werte auf dem Raster der\n    \/\/ angegebenen Bit-Tiefe, laesst sich die Oder-Maske auch hier bilden.\n    function oderAusGleitkomma(kanaele, bits) {\n        if (!bits || bits > 24) { return null; }\n        var f = Math.pow(2, bits - 1), oder = 0;\n        for (var c = 0; c < kanaele.length; c++) {\n            var d = kanaele[c];\n            for (var i = 0; i < d.length; i++) {\n                var s = d[i] * f;\n                if (s !== Math.floor(s)) { return null; }\n                oder |= s;\n            }\n        }\n        return oder;\n    }\n\n    function wirksameBits(oder, bits) {\n        if (oder === null || oder === undefined || !bits) { return null; }\n        if (oder === 0) { return 0; }\n        var frei = 0;\n        while (frei < bits &#038;&#038; ((oder >> frei) & 1) === 0) { frei++; }\n        return bits - frei;\n    }<\/p>\n<p>    \/\/ ---- Messung in Scheiben ------------------------------------------------\n    function messungAnlegen(kanaele, fs, schwelleVoll) {\n        var anzahl = kanaele.length, n = anzahl ? kanaele[0].length : 0, k = [];\n        for (var c = 0; c < anzahl; c++) {\n            k.push({ summe: 0, spitze: 0, tp: 0, voll: 0, stellen: 0, lauf: 0, flach: -1, ueber: 0, erster: -1, letzter: -1 });\n        }\n        return { kanaele: kanaele, fs: fs, n: n, anzahl: anzahl, schwelleVoll: schwelleVoll, k: k,\n                 kanal: 0, pos: 0, ring: new Float64Array(24), rp: 0, diffMax: 0 };\n    }\n\n    function tpNachlauf(m, s) {\n        var P0 = TP_PHASEN[0], P1 = TP_PHASEN[1], P2 = TP_PHASEN[2], P3 = TP_PHASEN[3];\n        for (var nach = 0; nach < 12; nach++) {\n            m.ring[m.rp] = 0; m.ring[m.rp + 12] = 0;\n            var o = m.rp + 12, q0 = 0, q1 = 0, q2 = 0, q3 = 0;\n            for (var t = 0; t < 12; t++) {\n                var v = m.ring[o - t];\n                q0 += P0[t] * v; q1 += P1[t] * v; q2 += P2[t] * v; q3 += P3[t] * v;\n            }\n            m.rp = m.rp === 11 ? 0 : m.rp + 1;\n            s.tp = Math.max(s.tp, Math.abs(q0), Math.abs(q1), Math.abs(q2), Math.abs(q3));\n        }\n        s.tp = Math.max(s.tp, s.spitze);\n    }\n\n    \/\/ Verarbeitet hoechstens \"budget\" Abtastwerte; true, wenn alle Kanaele durch sind.\n    function messungSchritt(m, budget) {\n        var P0 = TP_PHASEN[0], P1 = TP_PHASEN[1], P2 = TP_PHASEN[2], P3 = TP_PHASEN[3];\n        while (budget > 0 && m.kanal < m.anzahl) {\n            var c = m.kanal, d = m.kanaele[c], s = m.k[c], ende = Math.min(m.n, m.pos + budget);\n            var ring = m.ring, rp = m.rp, sv = m.schwelleVoll;\n            var summe = s.summe, spitze = s.spitze, tp = s.tp, voll = s.voll, stellen = s.stellen, lauf = s.lauf, flach = s.flach;\n            var ueber = s.ueber, erster = s.erster, letzter = s.letzter;\n            var links = c === 1 &#038;&#038; m.anzahl === 2 ? m.kanaele[0] : null, diffMax = m.diffMax;\n            for (var i = m.pos; i < ende; i++) {\n                var x = d[i], ax = x < 0 ? -x : x;\n                summe += x;\n                if (ax > spitze) { spitze = ax; }\n                \/\/ Geclippt ist, was flach abgeschnitten ist: derselbe Betrag an der\n                \/\/ Vollaussteuerung mehrmals hintereinander. Schwankende Werte ueber 1\n                \/\/ in einer Gleitkommadatei sind keine Stelle, sondern Ueberschreitung.\n                if (ax >= sv) {\n                    voll++;\n                    if (ax === flach) { lauf++; } else { lauf = 1; flach = ax; }\n                    if (lauf === 3) { stellen++; }\n                } else { lauf = 0; flach = -1; }\n                if (ax > 1) { ueber++; }\n                if (ax > STILLE) { if (erster < 0) { erster = i; } letzter = i; }\n                if (links) { var df = x - links[i]; if (df < 0) { df = -df; } if (df > diffMax) { diffMax = df; } }<\/p>\n<p>                \/\/ True Peak: Ringpuffer doppelt beschrieben, damit die zwoelf\n                \/\/ letzten Werte zusammenhaengend lesbar sind.\n                ring[rp] = x; ring[rp + 12] = x;\n                var o = rp + 12, s0 = 0, s1 = 0, s2 = 0, s3 = 0;\n                for (var t = 0; t < 12; t++) {\n                    var v = ring[o - t];\n                    s0 += P0[t] * v; s1 += P1[t] * v; s2 += P2[t] * v; s3 += P3[t] * v;\n                }\n                rp = rp === 11 ? 0 : rp + 1;\n                if (s0 < 0) { s0 = -s0; } if (s1 < 0) { s1 = -s1; } if (s2 < 0) { s2 = -s2; } if (s3 < 0) { s3 = -s3; }\n                if (s0 > tp) { tp = s0; } if (s1 > tp) { tp = s1; } if (s2 > tp) { tp = s2; } if (s3 > tp) { tp = s3; }\n            }\n            budget -= ende - m.pos;\n            m.pos = ende; m.rp = rp; m.diffMax = diffMax;\n            s.summe = summe; s.spitze = spitze; s.tp = tp; s.voll = voll; s.stellen = stellen; s.lauf = lauf; s.flach = flach;\n            s.ueber = ueber; s.erster = erster; s.letzter = letzter;\n            if (m.pos >= m.n) {\n                tpNachlauf(m, s);\n                m.kanal++; m.pos = 0; m.ring = new Float64Array(24); m.rp = 0;\n            }\n        }\n        return m.kanal >= m.anzahl;\n    }<\/p>\n<p>    function messungAuswerten(m) {\n        var e = { n: m.n, fs: m.fs, anzahl: m.anzahl, dauer: m.n \/ m.fs, spitze: 0, tp: 0, voll: 0, stellen: 0,\n                  ueber: 0, dc: 0, erster: -1, letzter: -1, anfangWert: 0, endeWert: 0,\n                  gleich: false, stumm: [] };\n        for (var c = 0; c < m.anzahl; c++) {\n            var s = m.k[c], d = m.kanaele[c];\n            e.spitze = Math.max(e.spitze, s.spitze);\n            e.tp = Math.max(e.tp, s.tp);\n            e.voll += s.voll; e.stellen += s.stellen; e.ueber += s.ueber;\n            e.dc = Math.max(e.dc, m.n ? Math.abs(s.summe \/ m.n) : 0);\n            if (s.erster >= 0 && (e.erster < 0 || s.erster < e.erster)) { e.erster = s.erster; }\n            if (s.letzter > e.letzter) { e.letzter = s.letzter; }\n            if (m.n) {\n                e.anfangWert = Math.max(e.anfangWert, Math.abs(d[0]));\n                e.endeWert = Math.max(e.endeWert, Math.abs(d[m.n - 1]));\n            }\n        }\n        for (var k = 0; k < m.anzahl; k++) { if (m.k[k].spitze === 0 &#038;&#038; e.spitze > 0) { e.stumm.push(k + 1); } }\n        e.gleich = m.anzahl === 2 && e.spitze > 0 && m.diffMax === 0;\n        return e;\n    }<\/p>\n<p>    function messen(kanaele, fs, schwelleVoll) {\n        if (!kanaele || !kanaele.length || !kanaele[0].length || !fs) { return null; }\n        var m = messungAnlegen(kanaele, fs, schwelleVoll);\n        while (!messungSchritt(m, 1 << 30)) { \/* weiter *\/ }\n        return messungAuswerten(m);\n    }\n\n    \/\/ Ab diesem Betrag steht ein Wert auf Vollaussteuerung.\n    function vollSchwelle(info) {\n        if (info.ganzzahl &#038;&#038; info.bits) { var f = Math.pow(2, info.bits - 1); return (f - 1) \/ f; }\n        return 1;\n    }\n\n    \/\/ ---- Befunde ------------------------------------------------------------\n    function db(wert) { return wert > 0 ? 20 * Math.log10(wert) : -Infinity; }\n    function runden(wert, stellen) { var f = Math.pow(10, stellen); return Math.round(wert * f) \/ f; }<\/p>\n<p>    function isrcNormal(s) { return String(s || '').replace(\/^ISRC[:\\s]*\/i, '').replace(\/[\\s\\-]\/g, '').toUpperCase(); }\n    function isrcGut(s) { return \/^[A-Z]{2}[A-Z0-9]{3}[0-9]{7}$\/.test(isrcNormal(s)); }<\/p>\n<p>    \/\/ Gibt je Pruefpunkt {id, stufe, schluessel, werte, wert} zurueck; die Texte\n    \/\/ setzt die Oberflaeche ein. stufe: ok, hinweis, problem, info, offen.\n    function befunde(info, e, wirksam) {\n        var liste = [];\n        function b(id, stufe, schluessel, werte, wert) {\n            liste.push({ id: id, stufe: stufe, schluessel: schluessel, werte: werte || {}, wert: wert === undefined ? null : wert });\n        }\n        \/\/ Format\n        if (info.verlustfrei === true) { b('format', 'ok', 'b_format_verlustfrei', { format: info.format }, info.format); }\n        else if (info.verlustfrei === false) { b('format', 'problem', 'b_format_verlustbehaftet', { format: info.format }, info.format); }\n        else { b('format', 'hinweis', 'b_format_unbekannt', { format: info.format || '' }, info.format); }\n        \/\/ Abtastrate\n        if (!info.rate) { b('rate', 'offen', 'b_offen_kopf'); }\n        else if (RATEN_APPLE.indexOf(info.rate) !== -1) { b('rate', 'ok', 'b_rate_ok', { rate: info.rate }, { hz: info.rate }); }\n        else { b('rate', 'problem', 'b_rate_andere', { rate: info.rate }, { hz: info.rate }); }\n        \/\/ Bit-Tiefe\n        if (info.verlustfrei === false) { b('bits', 'info', 'b_bits_verlustbehaftet'); }\n        else if (!info.bits) { b('bits', 'offen', 'b_offen_kopf'); }\n        else if (info.gleitkomma) { b('bits', 'hinweis', 'b_bits_float', { bits: info.bits }, { bits: info.bits, float: true }); }\n        else if (info.bits === 24) { b('bits', 'ok', 'b_bits_24', { bits: 24 }, { bits: 24 }); }\n        else if (info.bits === 16) { b('bits', 'ok', 'b_bits_16', { bits: 16 }, { bits: 16 }); }\n        else if (info.bits < 16) { b('bits', 'problem', 'b_bits_wenig', { bits: info.bits }, { bits: info.bits }); }\n        else { b('bits', 'hinweis', 'b_bits_andere', { bits: info.bits }, { bits: info.bits }); }\n        \/\/ Wirksame Bits (Bit-Padding)\n        if (info.verlustfrei !== false &#038;&#038; e) {\n            if (e.spitze === 0) { b('wirksam', 'offen', 'b_wirksam_stille'); }\n            else if (info.gleitkomma &#038;&#038; info.alle16) { b('wirksam', 'problem', 'b_wirksam_float16', { bits: info.bits }, { bits: 16 }); }\n            else if (info.gleitkomma &#038;&#038; info.alle24) { b('wirksam', 'ok', 'b_wirksam_float24', { bits: info.bits }, { bits: 24 }); }\n            else if (info.gleitkomma) { b('wirksam', 'ok', 'b_wirksam_float', { bits: info.bits }, { bits: info.bits, float: true }); }\n            else if (wirksam === null || wirksam === undefined) { b('wirksam', 'offen', 'b_wirksam_offen'); }\n            else if (wirksam >= info.bits) { b('wirksam', 'ok', 'b_wirksam_voll', { bits: info.bits }, { bits: wirksam }); }\n            else if (info.bits > 16 && wirksam <= 16) { b('wirksam', 'problem', 'b_wirksam_aufgefuellt', { wirksam: wirksam, bits: info.bits }, { bits: wirksam }); }\n            else { b('wirksam', 'hinweis', 'b_wirksam_weniger', { wirksam: wirksam, bits: info.bits }, { bits: wirksam }); }\n        }\n        \/\/ Kanaele\n        var anzahl = e ? e.anzahl : info.kanaeleAnzahl;\n        if (!anzahl) { b('kanaele', 'offen', 'b_offen_kopf'); }\n        else if (anzahl === 2) { b('kanaele', 'ok', 'b_kanaele_2', {}, anzahl); }\n        else if (anzahl === 1) { b('kanaele', 'hinweis', 'b_kanaele_1', {}, anzahl); }\n        else { b('kanaele', 'hinweis', 'b_kanaele_mehr', { n: anzahl }, anzahl); }\n\n        if (!e) { b('messung', 'offen', 'b_offen_ton'); return liste; }\n\n        b('dauer', 'info', 'b_dauer', {}, { s: e.dauer });\n        \/\/ Spitzen\n        if (e.voll > 0) { b('spitze', 'hinweis', 'b_spitze_voll', { n: e.voll }, { dbfs: db(e.spitze) }); }\n        else { b('spitze', 'ok', 'b_spitze_ok', {}, { dbfs: db(e.spitze) }); }\n        if (e.stellen > 0) { b('clipping', 'problem', 'b_clipping', { n: e.stellen }, { n: e.stellen }); }\n        else { b('clipping', 'ok', 'b_clipping_keine', {}, { n: 0 }); }\n        if (!info.ganzzahl) {\n            if (e.ueber > 0) { b('ueber', 'problem', 'b_ueber', { n: e.ueber }, { n: e.ueber }); }\n            else { b('ueber', 'ok', 'b_ueber_keine', {}, { n: 0 }); }\n        }\n        var tpDb = runden(db(e.tp), 1);\n        if (tpDb > 0) { b('truepeak', 'problem', 'b_tp_problem', {}, { dbtp: db(e.tp) }); }\n        else if (tpDb > -1) { b('truepeak', 'hinweis', 'b_tp_hinweis', {}, { dbtp: db(e.tp) }); }\n        else { b('truepeak', 'ok', 'b_tp_ok', {}, { dbtp: db(e.tp) }); }\n        \/\/ Gleichanteil\n        if (e.dc >= DC_GRENZE) { b('dc', 'hinweis', 'b_dc_hoch', {}, { dbfs: db(e.dc) }); }\n        else { b('dc', 'ok', 'b_dc_ok', {}, { dbfs: db(e.dc) }); }\n        \/\/ Stille und Spruenge\n        if (e.erster < 0) {\n            b('stille_anfang', 'problem', 'b_stille_ganz', {}, null);\n        } else {\n            var vorne = e.erster \/ e.fs, hinten = (e.n - 1 - e.letzter) \/ e.fs;\n            if (vorne >= STILLE_ANFANG_S) { b('stille_anfang', 'hinweis', 'b_stille_anfang_lang', {}, { s: vorne }); }\n            else { b('stille_anfang', 'ok', 'b_stille_anfang_ok', {}, { s: vorne }); }\n            if (hinten >= STILLE_ENDE_S) { b('stille_ende', 'hinweis', 'b_stille_ende_lang', {}, { s: hinten }); }\n            else { b('stille_ende', 'ok', 'b_stille_ende_ok', {}, { s: hinten }); }\n        }\n        var vorneSprung = e.anfangWert >= SPRUNG, hintenSprung = e.endeWert >= SPRUNG;\n        var sprungWert = { anfang: db(e.anfangWert), ende: db(e.endeWert) };\n        if (vorneSprung && hintenSprung) { b('sprung', 'hinweis', 'b_sprung_beide', {}, sprungWert); }\n        else if (vorneSprung) { b('sprung', 'hinweis', 'b_sprung_anfang', {}, sprungWert); }\n        else if (hintenSprung) { b('sprung', 'hinweis', 'b_sprung_ende', {}, sprungWert); }\n        else { b('sprung', 'ok', 'b_sprung_ok', {}, sprungWert); }\n        \/\/ Kanalvergleich\n        if (e.anzahl >= 2) {\n            if (e.stumm.length) { b('kanalvergleich', 'problem', 'b_kanal_stumm', { kanal: e.stumm.join(', ') }, null); }\n            else if (e.gleich) { b('kanalvergleich', 'hinweis', 'b_kanal_gleich', {}, null); }\n            else { b('kanalvergleich', 'ok', 'b_kanal_ok', {}, null); }\n        }\n        return liste;\n    }<\/p>\n<p>    function tagBefunde(tags) {\n        var liste = [];\n        function b(id, stufe, schluessel, werte, wert) {\n            liste.push({ id: id, stufe: stufe, schluessel: schluessel, werte: werte || {}, wert: wert === undefined ? null : wert });\n        }\n        function erster(feld) { for (var i = 0; i < feld.length; i++) { if (feld[i].wert) { return feld[i]; } } return null; }\n        var t = erster(tags.titel), k = erster(tags.kuenstler);\n        if (t) { b('titel', 'ok', 'b_titel_da', { ort: t.ort }, t.wert); } else { b('titel', 'info', 'b_titel_fehlt'); }\n        if (k) { b('kuenstler', 'ok', 'b_kuenstler_da', { ort: k.ort }, k.wert); } else { b('kuenstler', 'info', 'b_kuenstler_fehlt'); }\n\n        var codes = tags.isrc.filter(function (x) { return x.wert; });\n        var richtig = codes.filter(function (x) { return \/^(tsrc|vorbis|mp4_frei|mdta)$\/.test(x.ort) &#038;&#038; isrcGut(x.wert); });\n        var txxx = codes.filter(function (x) { return x.ort === 'txxx' &#038;&#038; isrcGut(x.wert); });\n        var riff = codes.filter(function (x) { return x.ort === 'riff_isrc'; });\n        var verschieden = {};\n        codes.forEach(function (x) { if (isrcGut(x.wert) &#038;&#038; x.ort !== 'riff_isrc') { verschieden[isrcNormal(x.wert)] = 1; } });\n        var falsch = codes.filter(function (x) { return x.ort !== 'riff_isrc' &#038;&#038; !isrcGut(x.wert); });\n        if (Object.keys(verschieden).length > 1) { b('isrc', 'problem', 'b_isrc_mehrere', { n: Object.keys(verschieden).length }, Object.keys(verschieden).join(', ')); }\n        else if (falsch.length) { b('isrc', 'problem', 'b_isrc_form', { ort: falsch[0].ort }, falsch[0].wert); }\n        else if (richtig.length) { b('isrc', 'ok', 'b_isrc_ok', { ort: richtig[0].ort }, isrcNormal(richtig[0].wert)); }\n        else if (txxx.length) { b('isrc', 'hinweis', 'b_isrc_txxx', { ort: 'txxx' }, isrcNormal(txxx[0].wert)); }\n        else if (riff.length) { b('isrc', 'hinweis', 'b_isrc_riff', { ort: 'riff_isrc' }, riff[0].wert); }\n        else { b('isrc', 'hinweis', 'b_isrc_fehlt'); }<\/p>\n<p>        var bilder = tags.cover.slice().sort(function (x, y) { return (x.bildtyp === 3 ? 0 : 1) - (y.bildtyp === 3 ? 0 : 1); });\n        var c = bilder[0];\n        if (!c) { b('cover', 'info', 'b_cover_fehlt'); }\n        else if (c.typ !== 'JPEG' && c.typ !== 'PNG') { b('cover', 'problem', 'b_cover_format', { typ: c.typ || '?' }, c); }\n        else if (!c.breite || !c.hoehe) { b('cover', 'hinweis', 'b_cover_masse', {}, c); }\n        else if (c.breite !== c.hoehe) { b('cover', 'problem', 'b_cover_quadrat', { breite: c.breite, hoehe: c.hoehe }, c); }\n        else if (c.breite < COVER_MINDEST) { b('cover', 'problem', 'b_cover_klein', { breite: c.breite, hoehe: c.hoehe }, c); }\n        else if (c.breite < COVER_EMPFOHLEN) { b('cover', 'hinweis', 'b_cover_mittel', { breite: c.breite, hoehe: c.hoehe }, c); }\n        else { b('cover', 'ok', 'b_cover_ok', { breite: c.breite, hoehe: c.hoehe }, c); }\n        return liste;\n    }\n\n    function gesamtUrteil(liste) {\n        var p = 0, h = 0;\n        liste.forEach(function (x) { if (x.stufe === 'problem') { p++; } else if (x.stufe === 'hinweis') { h++; } });\n        return { stufe: p ? 'problem' : (h ? 'hinweis' : 'ok'), probleme: p, hinweise: h };\n    }\n    \/\/ KERN-ENDE --------------------------------------------------------------\n\n    function el(id) { return document.getElementById(id); }\n    function satz(schluessel, werte) {\n        var s = T[schluessel] || '';\n        return s.replace(\/\\{(\\w+)\\}\/g, function (_, k) { return werte &#038;&#038; werte[k] !== undefined ? werte[k] : ''; });\n    }\n    var NB = '\u00a0';\n    function zahl(wert, stellen) {\n        if (wert === -Infinity) { return '\u2212\u221e'; }\n        if (wert === null || wert === undefined || !isFinite(wert)) { return '\u2013'; }\n        var s = Number(wert).toFixed(stellen === undefined ? 1 : stellen);\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 ganz(n) {\n        var s = String(Math.round(n)), t = T.tausender || '';\n        return t ? s.replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, t) : s;\n    }\n    function dauerText(s) {\n        if (s < 60) { return zahl(s, 2) + NB + 's'; }\n        var min = Math.floor(s \/ 60), rest = s - min * 60;\n        return min + NB + 'min ' + zahl(rest, 1) + NB + 's';\n    }\n    function ortText(ort) { return T['ort_' + ort] || ort; }\n\n    \/\/ Anzeigewert je Pruefpunkt\n    function wertText(x) {\n        var w = x.wert;\n        if (w === null || w === undefined) { return '\u2013'; }\n        switch (x.id) {\n            case 'format': return String(w);\n            case 'rate': return zahl(w.hz \/ 1000, w.hz % 1000 ? 1 : 0) + NB + 'kHz';\n            case 'bits': case 'wirksam': return w.bits + NB + 'Bit' + (w.float ? ' ' + T.wert_float : '');\n            case 'kanaele': return String(w);\n            case 'dauer': return dauerText(w.s);\n            case 'spitze': case 'dc': return zahl(w.dbfs, 1) + NB + 'dBFS';\n            case 'truepeak': return zahl(w.dbtp, 1) + NB + 'dBTP';\n            case 'clipping': case 'ueber': return ganz(w.n);\n            case 'stille_anfang': case 'stille_ende': return zahl(w.s, w.s < 10 ? 2 : 1) + NB + 's';\n            case 'sprung': return zahl(w.anfang, 1) + ' \/ ' + zahl(w.ende, 1) + NB + 'dBFS';\n            case 'cover': return w.breite &#038;&#038; w.hoehe ? w.breite + ' \u00d7 ' + w.hoehe + NB + 'px' : (w.typ || '\u2013');\n            default: return String(w);\n        }\n    }\n    function befundText(x) {\n        var werte = {};\n        Object.keys(x.werte).forEach(function (k) {\n            var v = x.werte[k];\n            if (k === 'ort') { werte[k] = ortText(v); }\n            else if (k === 'rate') { werte[k] = zahl(v \/ 1000, v % 1000 ? 1 : 0) + NB + 'kHz'; }\n            else if (typeof v === 'number') { werte[k] = ganz(v); }\n            else { werte[k] = v; }\n        });\n        return satz(x.schluessel, werte);\n    }\n\n    function tagZeilen(tags) {\n        var zeilen = [];\n        tags.titel.forEach(function (t) { zeilen.push([T.f_titel, t.wert, ortText(t.ort)]); });\n        tags.kuenstler.forEach(function (t) { zeilen.push([T.f_kuenstler, t.wert, ortText(t.ort)]); });\n        tags.isrc.forEach(function (t) { zeilen.push([T.f_isrc, t.wert, ortText(t.ort)]); });\n        tags.cover.forEach(function (c) {\n            var w = (c.typ || '?') + (c.breite &#038;&#038; c.hoehe ? ', ' + c.breite + ' \u00d7 ' + c.hoehe + NB + 'px' : '') + ', ' + ganz(c.bytes) + NB + 'Byte';\n            zeilen.push([T.f_cover, w, ortText(c.ort)]);\n        });\n        return zeilen;\n    }\n\n    function bericht(ergebnis) {\n        var z = [T.bericht_kopf + ': ' + (ergebnis.name || '')];\n        ergebnis.liste.forEach(function (x) {\n            z.push('[' + T['stufe_' + x.stufe] + '] ' + T['p_' + x.id] + ': ' + wertText(x) + ' \u2013 ' + befundText(x));\n        });\n        var g = ergebnis.gesamt;\n        z.push(satz('gesamt_' + g.stufe, { p: g.probleme, h: g.hinweise }));\n        return z.join('\\n');\n    }\n\n    \/\/ ---- Darstellung -------------------------------------------------------\n    function darstellen(ergebnis) {\n        var liste = el('rp-liste'), tags = el('rp-tags'), gesamt = el('rp-gesamt');\n        if (!liste) { return ergebnis; }\n        var g = ergebnis.gesamt;\n        gesamt.className = 'rp-gesamt rp-g-' + g.stufe;\n        gesamt.textContent = '';\n        var kopf = document.createElement('div');\n        kopf.className = 'rp-gesamt-kopf';\n        kopf.textContent = satz('gesamt_' + g.stufe, { p: g.probleme, h: g.hinweise });\n        var txt = document.createElement('div');\n        txt.className = 'rp-klein';\n        txt.textContent = satz('gesamt_text_' + g.stufe, { name: ergebnis.name || '' });\n        gesamt.appendChild(kopf); gesamt.appendChild(txt);\n\n        liste.textContent = '';\n        ergebnis.liste.forEach(function (x) {\n            var tr = document.createElement('tr');\n            tr.setAttribute('data-id', x.id);\n            var td1 = document.createElement('td');\n            var marke = document.createElement('span');\n            marke.className = 'rp-stufe rp-s-' + x.stufe;\n            marke.textContent = T['stufe_' + x.stufe];\n            var name = document.createElement('div');\n            name.className = 'rp-name';\n            name.textContent = T['p_' + x.id];\n            td1.appendChild(marke); td1.appendChild(name);\n            var td2 = document.createElement('td'); td2.className = 'rp-wert'; td2.textContent = wertText(x);\n            var td3 = document.createElement('td'); td3.className = 'rp-text'; td3.textContent = befundText(x);\n            tr.appendChild(td1); tr.appendChild(td2); tr.appendChild(td3);\n            liste.appendChild(tr);\n        });\n\n        tags.textContent = '';\n        var zeilen = tagZeilen(ergebnis.info.tags);\n        if (!zeilen.length) { zeilen.push([T.wert_keine_tags, '', '']); }\n        zeilen.forEach(function (z) {\n            var tr = document.createElement('tr');\n            z.forEach(function (w, i) {\n                var td = document.createElement('td');\n                if (i > 0) { td.className = 'rp-wert'; }\n                td.textContent = w;\n                tr.appendChild(td);\n            });\n            tags.appendChild(tr);\n        });\n        el('rp-ausgabe').hidden = false;\n        el('rp-fehler').hidden = true;\n        return ergebnis;\n    }<\/p>\n<p>    function fehlerZeigen(s) {\n        var f = el('rp-fehler');\n        if (!f) { return; }\n        f.textContent = s;\n        f.hidden = false;\n        el('rp-ausgabe').hidden = true;\n        el('rp-status').textContent = '';\n    }<\/p>\n<p>    \/\/ ---- Ablauf ------------------------------------------------------------\n    var tick = typeof MessageChannel !== 'undefined' ? new MessageChannel() : null, schlange = [];\n    if (tick) { tick.port1.onmessage = function () { var f = schlange.shift(); if (f) { f(); } }; }\n    function spaeter(f) { if (tick) { schlange.push(f); tick.port2.postMessage(0); } else { setTimeout(f, 0); } }<\/p>\n<p>    function messenAsync(kanaele, fs, sv, fortschritt) {\n        return new Promise(function (ok, fehler) {\n            if (!kanaele || !kanaele.length || !kanaele[0].length || !fs) { ok(null); return; }\n            var m = messungAnlegen(kanaele, fs, sv), gesamt = m.n * m.anzahl || 1;\n            function schritt() {\n                try {\n                    var fertig = messungSchritt(m, 1 << 18);\n                    if (fortschritt) { fortschritt(Math.min(1, (m.kanal * m.n + m.pos) \/ gesamt)); }\n                    if (fertig) { ok(messungAuswerten(m)); } else { spaeter(schritt); }\n                } catch (e) { fehler(e); }\n            }\n            spaeter(schritt);\n        });\n    }\n\n    function dekodieren(puffer, rate) {\n        return new Promise(function (ok, fehler) {\n            var Ctx = window.OfflineAudioContext || window.webkitOfflineAudioContext;\n            if (!Ctx) { fehler(new Error('webaudio')); return; }\n            var ctx, erledigt = false;\n            try { ctx = new Ctx(1, 1, rate); } catch (e) { ctx = new Ctx(1, 1, 48000); }\n            function gut(buf) { if (!erledigt) { erledigt = true; ok(buf); } }\n            function schlecht(e) { if (!erledigt) { erledigt = true; fehler(e || new Error('dekodieren')); } }\n            setTimeout(function () { schlecht(new Error('zeit')); }, 60000);\n            try {\n                var p = ctx.decodeAudioData(puffer, gut, schlecht);\n                if (p &#038;&#038; typeof p.then === 'function') { p.then(gut, schlecht); }\n            } catch (e) { schlecht(e); }\n        });\n    }\n\n    var letztes = null;\n    \/\/ optionen.dekodieren: false laesst den Decoder des Browsers aus (Pruefung).\n    function verarbeiten(puffer, name, optionen) {\n        optionen = optionen || {};\n        var info;\n        try { info = lesen(puffer); } catch (x) { info = null; }\n        if (!info || (info.fehler &#038;&#038; !info.format)) { fehlerZeigen(T.fehler_format); return Promise.resolve(null); }\n        var status = el('rp-status');\n        var wegZumTon;\n        if (info.kanaele) { wegZumTon = Promise.resolve(info.kanaele); }\n        else if (optionen.dekodieren === false || info.fehler === 'codec') { wegZumTon = Promise.resolve(null); }\n        else {\n            if (status) { status.textContent = T.status_dekodieren; }\n            var rate = info.rate &#038;&#038; info.rate >= 3000 && info.rate <= 768000 ? info.rate : 48000;\n            wegZumTon = dekodieren(puffer.slice(0), rate).then(function (buf) {\n                var k = [];\n                for (var c = 0; c < buf.numberOfChannels; c++) { k.push(buf.getChannelData(c)); }\n                if (buf.sampleRate !== info.rate) { info.rateDekodiert = buf.sampleRate; }\n                if (info.verlustfrei &#038;&#038; info.ganzzahl &#038;&#038; !info.rateDekodiert) { info.oder = oderAusGleitkomma(k, info.bits); }\n                return k;\n            }, function () { return null; });\n        }\n        return wegZumTon.then(function (kanaele) {\n            var fs = info.rateDekodiert || info.rate;\n            return messenAsync(kanaele, fs, vollSchwelle(info), function (anteil) {\n                if (status) { status.textContent = satz('status_messen', { p: Math.round(anteil * 100) }); }\n            });\n        }).then(function (e) {\n            var wirksam = info.ganzzahl ? wirksameBits(info.oder, info.bits) : null;\n            var liste = befunde(info, e, wirksam).concat(tagBefunde(info.tags));\n            var ergebnis = { name: name || '', info: info, messung: e, liste: liste, gesamt: gesamtUrteil(liste) };\n            letztes = ergebnis;\n            if (status) { status.textContent = ''; }\n            return darstellen(ergebnis);\n        });\n    }\n\n    function dateiNehmen(datei) {\n        if (!datei) { return; }\n        var leser = new FileReader();\n        el('rp-status').textContent = T.status_lesen;\n        leser.onload = function () {\n            verarbeiten(leser.result, datei.name).then(null, function () { fehlerZeigen(T.fehler_lesen); });\n        };\n        leser.onerror = function () { fehlerZeigen(T.fehler_lesen); };\n        try { leser.readAsArrayBuffer(datei); } catch (x) { fehlerZeigen(T.fehler_lesen); }\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.RP = {\n        T: T, lesen: lesen, id3Lesen: id3Lesen, vorbisKommentar: vorbisKommentar, bildMasse: bildMasse,\n        mp4Lesen: mp4Lesen, oggLesen: oggLesen, pcmLesen: pcmLesen, messen: messen, vollSchwelle: vollSchwelle,\n        wirksameBits: wirksameBits, oderAusGleitkomma: oderAusGleitkomma, befunde: befunde, tagBefunde: tagBefunde,\n        gesamtUrteil: gesamtUrteil, isrcGut: isrcGut, isrcNormal: isrcNormal, wertText: wertText,\n        befundText: befundText, bericht: bericht, verarbeiten: verarbeiten, zahl: zahl,\n        letztes: function () { return letztes; }\n    };\n\n    var zone = el('rp-zone'), eingabe = el('rp-datei'), knopf = el('rp-knopf');\n    if (!zone || !eingabe || !knopf) { return; }\n    knopf.addEventListener('click', function () { eingabe.click(); });\n    eingabe.addEventListener('change', function () { dateiNehmen(eingabe.files &#038;&#038; eingabe.files[0]); eingabe.value = ''; });\n    ['dragenter', 'dragover'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.add('rp-ueber'); });\n    });\n    ['dragleave', 'drop'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.remove('rp-ueber'); });\n    });\n    zone.addEventListener('drop', function (ev) {\n        ev.preventDefault();\n        dateiNehmen(ev.dataTransfer &#038;&#038; ev.dataTransfer.files &#038;&#038; ev.dataTransfer.files[0]);\n    });\n    var kopieren = el('rp-kopieren'), kopiert = el('rp-kopiert');\n    if (kopieren) {\n        kopieren.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; },\n                    function () { kopiert.textContent = T.kopieren_fehler; });\n            } else {\n                kopiert.textContent = T.kopieren_fehler;\n            }\n        });\n    }\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Liest eine WAV-, AIFF-, FLAC-, MP3-, M4A- oder Ogg-Datei im Browser und listet, was zwischen ihr und der Lieferung steht: Format, Samplerate und Bit-Tiefe gegen die Anforderungen von Apple, aufgef\u00fcllte Bits, Clipping, True Peak, Gleichanteil, Stille und Spr\u00fcnge an beiden Enden sowie Titel, K\u00fcnstler, ISRC und Cover aus den Tags.<\/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-20129","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>Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - 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\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Liest eine WAV-, AIFF-, FLAC-, MP3-, M4A- oder Ogg-Datei im Browser und listet, was zwischen ihr und der Lieferung steht: Format, Samplerate und Bit-Tiefe gegen die Anforderungen von Apple, aufgef\u00fcllte Bits, Clipping, True Peak, Gleichanteil, Stille und Spr\u00fcnge an beiden Enden sowie Titel, K\u00fcnstler, ISRC und Cover aus den Tags.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-23T16:54:14+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=\"2 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\\\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\\\/\",\"name\":\"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-23T16:48:18+00:00\",\"dateModified\":\"2026-09-23T16:54:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\\\/#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\":\"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen\"}]},{\"@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":"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - 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\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/","og_locale":"en_US","og_type":"article","og_title":"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - Lukas Wojcik - Blog","og_description":"Liest eine WAV-, AIFF-, FLAC-, MP3-, M4A- oder Ogg-Datei im Browser und listet, was zwischen ihr und der Lieferung steht: Format, Samplerate und Bit-Tiefe gegen die Anforderungen von Apple, aufgef\u00fcllte Bits, Clipping, True Peak, Gleichanteil, Stille und Spr\u00fcnge an beiden Enden sowie Titel, K\u00fcnstler, ISRC und Cover aus den Tags.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-09-23T16:54:14+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":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/","url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/","name":"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-23T16:48:18+00:00","dateModified":"2026-09-23T16:54:14+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/release-file-checker-sample-rate-bit-depth-peaks-isrc-cover\/#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":"Release-Datei-Pr\u00fcfer: Samplerate, Bit-Tiefe, Spitzen, Stille, ISRC und Cover vor dem Hochladen"}]},{"@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\/20129","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=20129"}],"version-history":[{"count":1,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20129\/revisions"}],"predecessor-version":[{"id":20132,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20129\/revisions\/20132"}],"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=20129"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}