107 lines
4.6 KiB
Bash
Executable file
107 lines
4.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-vgm.sh - Host gate for tools/vgm2song.py, the VGM-to-.song converter
|
|
# that brings tracker-made chip music (Furnace's, docs/Assets.adoc) to
|
|
# JoeyLib's chip tracker.
|
|
#
|
|
# 1. tests/host/vgmCheck.py synthetic: VGM files written to known register
|
|
# writes, converted and baked; every baked row must hold the voices worked
|
|
# out by hand.
|
|
# 2. With Furnace installed (./install.sh install furnace): every SN76489 and
|
|
# AY-3-8910 demo song Furnace comes with that uses that chip alone is
|
|
# exported by Furnace to VGM and to audio (WAV), converted and baked; each
|
|
# must bake, and Furnace's own audio must sound the pitches the baked song
|
|
# plays (tests/host/vgmCheck.py pitch): at least PITCH_MIN_SONG percent of
|
|
# each song's pitched windows, PITCH_MIN_MEAN on average (a wrong clock or
|
|
# divider gives under 10). The demos are their authors' and stay where the
|
|
# installer put them; nothing made from them is kept.
|
|
#
|
|
# Usage: scripts/check-vgm.sh
|
|
# Exit: 0 PASS, 1 FAIL
|
|
set -uo pipefail
|
|
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
source "$repo/scripts/lib/joeyEnv.sh"
|
|
label=check-vgm
|
|
PITCH_MIN_SONG=40
|
|
PITCH_MIN_MEAN=75
|
|
FURNACE_SECONDS=300
|
|
DEMO_FOLDERS="sn7:sn ay8910:ay"
|
|
|
|
work=$(mktemp -d -t joeylib-vgm.XXXXXX)
|
|
trap 'rm -rf "$work"' EXIT
|
|
mkdir -p "$work/synthetic" "$work/demos" "$work/home"
|
|
|
|
synthetic=$(python3 "$repo/tests/host/vgmCheck.py" synthetic "$repo" "$work/synthetic")
|
|
status=$?
|
|
echo "$synthetic" | grep -v '^SYNTHETIC'
|
|
counts=$(echo "$synthetic" | sed -n 's/^SYNTHETIC //p')
|
|
if [ "$status" -ne 0 ]; then
|
|
echo "$label: FAIL - synthetic checks $counts"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "${FURNACE:-}" ] || [ ! -x "${FURNACE:-}" ]; then
|
|
echo "$label: PASS (synthetic $counts; Furnace not installed, so no demo songs: ./install.sh install furnace)"
|
|
exit 0
|
|
fi
|
|
|
|
fails=""
|
|
songs=0
|
|
total=0
|
|
for spec in $DEMO_FOLDERS; do
|
|
folder=${spec%%:*}
|
|
chip=${spec##*:}
|
|
for fur in "$FURNACE_DEMOS/$folder"/*.fur; do
|
|
[ -f "$fur" ] || continue
|
|
name=$(basename "$fur" .fur | tr -c 'A-Za-z0-9_\n-' '_')
|
|
base="$work/demos/$name"
|
|
# Furnace keeps its settings under HOME: the work folder's, not ours.
|
|
if ! HOME="$work/home" timeout "$FURNACE_SECONDS" "$FURNACE" -loglevel error -vgmout "$base.vgm" "$fur" < /dev/null > /dev/null 2>&1 \
|
|
|| ! HOME="$work/home" timeout "$FURNACE_SECONDS" "$FURNACE" -loglevel error -output "$base.wav" "$fur" < /dev/null > /dev/null 2>&1; then
|
|
fails="${fails:+$fails; }$folder/$name: Furnace did not export it"
|
|
continue
|
|
fi
|
|
if ! python3 "$repo/tools/vgm2song.py" --chip "$chip" "$base.vgm" "$base.song" 2> "$base.warn"; then
|
|
fails="${fails:+$fails; }$folder/$name: $(tr '\n' ' ' < "$base.warn")"
|
|
continue
|
|
fi
|
|
# A song for more chips than this one sounds parts the conversion
|
|
# leaves out: no pitch to compare.
|
|
if grep -q 'other chips' "$base.warn"; then
|
|
echo "$label: $folder/$name: skipped (the song uses another chip too)"
|
|
continue
|
|
fi
|
|
if ! python3 "$repo/tools/songbake/songbake.py" "$base.song" "$base.jym" > /dev/null 2> "$base.bake"; then
|
|
fails="${fails:+$fails; }$folder/$name: songbake: $(grep -v warning "$base.bake" | tr '\n' ' ')"
|
|
continue
|
|
fi
|
|
result=$(python3 "$repo/tests/host/vgmCheck.py" pitch "$base.wav" "$base.jym" | sed -n 's/^PITCH //p')
|
|
matched=${result%%/*}
|
|
tested=${result##*/}
|
|
if [ -z "$tested" ] || [ "$tested" -eq 0 ]; then
|
|
fails="${fails:+$fails; }$folder/$name: no pitched window to compare"
|
|
continue
|
|
fi
|
|
percent=$((100 * matched / tested))
|
|
echo "$label: $folder/$name: $(sed -n 2p "$base.song" | cut -c3-); pitch $matched/$tested ($percent%)"
|
|
songs=$((songs + 1))
|
|
total=$((total + percent))
|
|
if [ "$percent" -lt "$PITCH_MIN_SONG" ]; then
|
|
fails="${fails:+$fails; }$folder/$name: pitch $percent% < $PITCH_MIN_SONG%"
|
|
fi
|
|
done
|
|
done
|
|
if [ "$songs" -eq 0 ]; then
|
|
fails="${fails:+$fails; }no demo song converted"
|
|
elif [ $((total / songs)) -lt "$PITCH_MIN_MEAN" ]; then
|
|
fails="${fails:+$fails; }mean pitch $((total / songs))% < $PITCH_MIN_MEAN%"
|
|
fi
|
|
if [ -n "$fails" ]; then
|
|
echo "$label: FAIL - $fails"
|
|
exit 1
|
|
fi
|
|
echo "$label: PASS (synthetic $counts; $songs Furnace demo songs convert, bake, and sound their pitches: mean $((total / songs))%)"
|