#!/bin/sh
# autopkgtest for sonivoxrender: render a minimal MIDI file with each
# available sound engine and check that raw PCM audio comes out.
#
# Note that no external soundfont is required: without -d/--dls, sonivoxrender
# falls back to the soundfont embedded in libsonivox.
set -eu

export LC_ALL=C

workdir="$AUTOPKGTEST_TMP/render-synthesis"
mkdir -p "$workdir"
midi="$workdir/minimal.mid"

# Format 0 MIDI file, 96 ticks per quarter note, tempo 500000 us per quarter
# note (120 bpm): a single middle-C note lasting exactly one quarter note,
# i.e. 0.5 s.
#
# The file is assembled with printf and octal escapes so that the test needs
# nothing beyond /bin/sh and coreutils. The track length below (026 = 22
# decimal) covers the 22 bytes that follow it.
{
    printf 'MThd\000\000\000\006\000\000\000\001\000\140'
    printf 'MTrk\000\000\000\026'
    printf '\000\377\121\003\007\241\040'   # meta: set tempo 500000 us/quarter
    printf '\000\300\000'                   # program change: piano
    printf '\000\220\074\144'               # note on: middle C, velocity 100
    printf '\140\200\074\000'               # 96 ticks later: note off
    printf '\000\377\057\000'               # meta: end of track
} > "$midi"

# sonivoxrender writes 16-bit signed stereo PCM at 44100 Hz to stdout, i.e.
# 4 bytes per frame. The note alone accounts for 0.5 s => 88200 bytes; any
# shorter output means the render was truncated.
min_bytes=$((44100 / 2 * 4))

# Sound engine 1 is the WT-only bank and engine 2 is the FM-only bank, both
# of which are part of the Debian build. Engine 3 (hybrid_22khz_mcu) is not
# compiled in upstream and makes sonivoxrender fail, so it is not tested.
for engine in 1 2; do
    pcm="$workdir/engine-$engine.pcm"

    if ! timeout 60 sonivoxrender -s "$engine" "$midi" > "$pcm"; then
        echo "sonivoxrender: rendering with sound engine $engine failed" >&2
        exit 1
    fi

    size=$(wc -c < "$pcm")
    if [ "$size" -lt "$min_bytes" ]; then
        echo "engine $engine: got $size bytes of PCM, expected at least $min_bytes" >&2
        exit 1
    fi

    # Peak amplitude and RMS across all samples. This rejects a truncated
    # render, a silent render, and a render that consists of nothing but a DC
    # offset or a single click, all of which a bare "any sample non-zero"
    # check would happily accept.
    stats=$(od -An -v -td2 -w2 "$pcm" | awk '
        {
            for (i = 1; i <= NF; i++) {
                v = $i
                if (v < 0) v = -v
                if (v > peak) peak = v
                sum += $i * $i
                n++
            }
        }
        END { printf "%.0f %.0f\n", peak, sqrt(sum / n) }
    ')
    peak=${stats% *}
    rms=${stats#* }

    # Reference values from a healthy render are peak ~8000-9000 and
    # RMS ~1800-2800, so these thresholds leave ample margin.
    if [ "$peak" -lt 1000 ] || [ "$rms" -lt 100 ]; then
        echo "engine $engine: PCM too quiet (peak=$peak rms=$rms)" >&2
        exit 1
    fi

    echo "engine $engine: $size bytes of PCM, peak=$peak rms=$rms"
done

# The two engines must not degrade into aliases of each other.
if cmp -s "$workdir/engine-1.pcm" "$workdir/engine-2.pcm"; then
    echo "sound engines 1 and 2 produced identical output" >&2
    exit 1
fi

# The parser must still reject input that is not a MIDI file at all.
if timeout 60 sonivoxrender -s 1 "$workdir/not-a-midi" > /dev/null 2>&1; then
    echo "sonivoxrender: accepted a nonexistent file" >&2
    exit 1
fi

echo "sonivoxrender rendered MIDI with all available sound engines"
