joeylib2/scripts/check-modplayer.sh

67 lines
2.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
# See LICENSE.md for license information.
# SPDX-License-Identifier: MIT
#
# check-modplayer.sh - Host gate for src/core/modPlayer.c, the module player
# every port that mixes .MOD in software plays through (DOS, the ST, the
# X68000, and the hosted ports). Builds tests/host/modPlayerHost.c, which
# includes the player, with the host cc and the address and undefined-
# behaviour sanitizers, and runs it: the Protracker behaviours the player
# keeps, where a song ends, the 8-bit and 16-bit outputs, and mangled
# modules played without reading outside the player's copy. When the
# Amiga's PTPlayer is installed, its period and vibrato tables are handed
# over too, and the player's must match them.
#
# Usage: scripts/check-modplayer.sh
# Exit: 0 PASS, 1 FAIL
set -uo pipefail
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source "$repo/scripts/lib/joeyEnv.sh"
label=check-modplayer
cc=${CC:-cc}
work=$(mktemp -d -t joeylib-modplayer.XXXXXX)
trap 'rm -rf "$work"' EXIT
cd "$repo"
if ! "$cc" -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -DJOEYLIB_PLATFORM_BLANK \
-Iinclude -Iinclude/joey -Isrc/core -Wall -Wextra -Werror \
tests/host/modPlayerHost.c -lm -o "$work/modPlayerHost"; then
echo "$label: FAIL - the harness did not build"
exit 1
fi
# PTPlayer's mt_PeriodTable, then its three vibrato tables, as numbers.
tables=()
asm="${AMIGA_PTPLAYER:-}/ptplayer.asm"
if [ -f "$asm" ]; then
python3 - "$asm" "$work/tables.txt" <<'EOF'
import re, sys
asm = open(sys.argv[1]).read()
def values(start, stop):
block = asm[asm.index(start):asm.index(stop, asm.index(start))]
out = []
for line in block.splitlines():
m = re.match(r'\s*dc\.[bw]\s+([^;]*)', line)
if m:
out += [int(v) for v in m.group(1).split(',')]
return out
periods = values('mt_PeriodTable:', '\n\n')
waves = values('mt_VibratoSineTable:', 'mt_VibratoSawTable:') + values('mt_VibratoSawTable:', 'mt_VibratoRectTable:') + values('mt_VibratoRectTable:', 'endc')
with open(sys.argv[2], 'w') as f:
f.write('periods ' + ' '.join(map(str, periods)) + '\nvibrato ' + ' '.join(map(str, waves)) + '\n')
EOF
tables=("$work/tables.txt")
fi
output=$("$work/modPlayerHost" "${tables[@]}" 2>&1)
status=$?
echo "$output" | grep -v '^MODPLAYER'
counts=$(sed -n 's/^MODPLAYER //p' <<< "$output")
if [ "$status" -ne 0 ]; then
echo "$label: FAIL - ${counts:-harness error} checks pass"
exit 1
fi
echo "$label: PASS ($counts checks: Protracker's behaviours, song ends, both outputs, and mangled modules, under the sanitizers)"