{"record":{"id":"ea46358df3adf301","repo":"SubtitleEdit/subtitleedit","slug":"peaks-file-must-have-1-or-2-channels","errorCode":null,"errorMessage":"Peaks file must have 1 or 2 channels.","messagePattern":"Peaks file must have 1 or 2 channels\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Media/WaveToVisualizer2.cs","lineNumber":792,"sourceCode":"            min = Math.Min(min, value);\n        }\n\n        return new WavePeak2((short)(short.MaxValue * max), (short)(short.MaxValue * min));\n    }\n\n    /// <summary>\n    /// Loads previously generated peaks from disk.\n    /// </summary>\n    internal WavePeakData2 LoadPeaks()\n    {\n        if (Header.BitsPerSample != 16)\n        {\n            throw new Exception(\"Peaks file must be 16 bits per sample.\");\n        }\n\n        if (Header.NumberOfChannels != 1 && Header.NumberOfChannels != 2)\n        {\n            throw new Exception(\"Peaks file must have 1 or 2 channels.\");\n        }\n\n        // load data\n        byte[] data = new byte[Header.DataChunkSize];\n        _stream.Position = Header.DataStartPosition;\n        _ = _stream.Read(data, 0, data.Length);\n\n        // read peak values\n        WavePeak2[] peaks = new WavePeak2[Header.LengthInSamples + 5];\n        int peakIndex = 0;\n        if (Header.NumberOfChannels == 2)\n        {\n            // max value in left channel, min value in right channel\n            int byteIndex = 0;\n            while (byteIndex < data.Length)\n            {\n                short max = (short)ReadValue16Bit(data, ref byteIndex);\n                short min = (short)ReadValue16Bit(data, ref byteIndex);","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Media/WaveToVisualizer2.cs#L774-L810","documentation":"Thrown by WavePeakData2.LoadPeaks when the peaks cache WAV header reports a channel count other than 1 or 2. The peak-reading logic only knows how to deserialize mono (single sample) or stereo (max/min pair) peak records; any other channel count is unparseable and would corrupt the peak array.","triggerScenarios":"LoadPeaks() is pointed at a multi-channel (e.g. 5.1 / 6-channel) WAV, or a file whose header was damaged so NumberOfChannels parses to an out-of-range value.","commonSituations":"Source audio had more than 2 channels and was mistakenly used as the peaks cache; corruption of the fmt chunk shifting the channels field; a third-party tool wrote a non-standard peaks file.","solutions":["Regenerate the peaks cache from a mono or stereo source.","Down-mix multi-channel audio to stereo before peak generation.","Guard: check Header.NumberOfChannels is 1 or 2 before LoadPeaks and regenerate otherwise.","Verify the cache file is the one produced by this application's GeneratePeaks path."],"exampleFix":"// before\nvar peaks = wave.LoadPeaks();\n\n// after\nif (wave.Header.NumberOfChannels is 1 or 2)\n    peaks = wave.LoadPeaks();\nelse\n    peaks = GeneratePeaksForCache();","handlingStrategy":"validation","validationCode":"if (wave.Header.NumberOfChannels is not (1 or 2))\n    throw new InvalidOperationException($\"Peaks cache must be 1 or 2 channels, got {wave.Header.NumberOfChannels}\");","typeGuard":"static bool IsSupportedChannelCount(WaveHeader2 h) => h.NumberOfChannels == 1 || h.NumberOfChannels == 2;","tryCatchPattern":"try { var peaks = wave.LoadPeaks(); }\ncatch (Exception ex) when (ex.Message.Contains(\"1 or 2 channels\")) { /* regenerate or down-mix */ }","preventionTips":["Down-mix multi-channel audio to stereo before peak generation.","Guard channel count before LoadPeaks.","Regenerate the peaks cache from a mono/stereo source.","Validate the cache file path is the generated one."],"tags":["wav","audio","peaks","validation","channels"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}