SubtitleEdit/subtitleedit · error · Exception

Peaks file must be 16 bits per sample.

Error message

Peaks file must be 16 bits per sample.

What it means

Thrown by WavePeakData2.LoadPeaks when the cached peaks WAV file's header does not report exactly 16 bits per sample. The peaks cache is itself stored as a WAV whose samples are pre-computed min/max peak shorts, so only 16-bit data is meaningful for the peak-reading loop that follows. Any other bit depth means the file is not a SubtitleEdit-generated peaks cache.

Source

Thrown at src/ui/Logic/Media/WaveToVisualizer2.cs:787

        for (var i = 1; i < count; i++)
        {
            float value = chunk[i];
            max = Math.Max(max, value);
            min = Math.Min(min, value);
        }

        return new WavePeak2((short)(short.MaxValue * max), (short)(short.MaxValue * min));
    }

    /// <summary>
    /// Loads previously generated peaks from disk.
    /// </summary>
    internal WavePeakData2 LoadPeaks()
    {
        if (Header.BitsPerSample != 16)
        {
            throw new Exception("Peaks file must be 16 bits per sample.");
        }

        if (Header.NumberOfChannels != 1 && Header.NumberOfChannels != 2)
        {
            throw new Exception("Peaks file must have 1 or 2 channels.");
        }

        // load data
        byte[] data = new byte[Header.DataChunkSize];
        _stream.Position = Header.DataStartPosition;
        _ = _stream.Read(data, 0, data.Length);

        // read peak values
        WavePeak2[] peaks = new WavePeak2[Header.LengthInSamples + 5];
        int peakIndex = 0;
        if (Header.NumberOfChannels == 2)
        {
            // max value in left channel, min value in right channel

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Regenerate the peaks cache (delete the existing peaks file and re-run peak generation) so it is written as 16-bit.
  2. Ensure LoadPeaks() is only called on the dedicated peaks cache path, never on the source audio file.
  3. If the peaks file format changed between versions, clear the cache directory.
  4. Guard the call: check Header.BitsPerSample == 16 before invoking LoadPeaks and fall back to generation.

Example fix

// before
var peaks = wave.LoadPeaks();

// after
WavePeakData2 peaks;
if (wave.Header.BitsPerSample == 16)
    peaks = wave.LoadPeaks();
else
    peaks = wave.GeneratePeaks(peakSampleRate);
Defensive patterns

Strategy: validation

Validate before calling

// before LoadPeaks
if (wave.Header.BitsPerSample != 16)
    throw new InvalidOperationException($"Peaks cache must be 16-bit, got {wave.Header.BitsPerSample}-bit");

Type guard

static bool IsPeaksCacheBitDepth(WaveHeader2 h) => h.BitsPerSample == 16;

Try / catch

try { var peaks = wave.LoadPeaks(); }
catch (Exception ex) when (ex.Message.Contains("16 bits per sample")) { peaks = wave.GeneratePeaks(peaksPerSecond); }

Prevention

When it happens

Trigger: Calling LoadPeaks() on a Wave object whose stream points at a regular audio WAV (8/24/32-bit) instead of the generated peaks cache, or on a peaks file produced by a different/older tool version that wrote a different bit depth.

Common situations: The peaks cache path was overwritten with the source audio; a user manually swapped the .wav; an upgrade changed the cache format and the stale file was not regenerated; pointing LoadPeaks at the original media instead of the generated peaks file.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/d89c5b7acf701060. Report an issue: GitHub.