100 lines
3.7 KiB
Bash
Executable file
100 lines
3.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# joeymod: convert a Protracker .MOD into the runtime form a target
|
|
# platform expects.
|
|
#
|
|
# Usage:
|
|
# joeymod input.mod output.mod -- passthrough copy + magic validation
|
|
# (DOS / ST runtimes detect song end
|
|
# inside libxmp-lite, so the file is
|
|
# used as-is)
|
|
# joeymod input.mod output.amod -- passthrough + E8FF stop-marker
|
|
# pattern injected at song end. The
|
|
# Amiga audio HAL relies on E8FF to
|
|
# honor PlayMod(loop=false) since
|
|
# PTPlayer has no native song-end
|
|
# signal. Other replayers ignore
|
|
# E8FF (or treat it as a filter
|
|
# toggle), so .amod is harmless if
|
|
# fed to the wrong port.
|
|
# joeymod input.mod output.ntp -- runs the PHP ntpconverter staged
|
|
# at toolchains/iigs/ntp/ntpconverter.php
|
|
# (NinjaTrackerPlus' .NTP runtime
|
|
# format on the IIgs)
|
|
#
|
|
# The output extension picks the conversion. Build rules per platform
|
|
# call this with whichever pair their HAL needs.
|
|
|
|
set -euo pipefail
|
|
|
|
if [[ $# -ne 2 ]]; then
|
|
echo "usage: joeymod input.mod output.{mod,amod,ntp}" >&2
|
|
exit 2
|
|
fi
|
|
|
|
in=$1
|
|
out=$2
|
|
|
|
if [[ ! -f $in ]]; then
|
|
echo "joeymod: input not found: $in" >&2
|
|
exit 2
|
|
fi
|
|
|
|
# All Protracker-derived .MOD variants store a 4-byte signature at
|
|
# offset 1080. Reject anything that does not match a known one --
|
|
# better to fail at build time than ship a corrupted audio asset.
|
|
magic=$(dd if="$in" bs=1 count=4 skip=1080 status=none)
|
|
case "$magic" in
|
|
M.K.|M!K!|FLT4|FLT8|6CHN|8CHN|CD81|OKTA|OCTA) ;;
|
|
*)
|
|
printf 'joeymod: %s does not look like a .MOD (magic %q at offset 1080)\n' "$in" "$magic" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
ext="${out##*.}"
|
|
ext="${ext,,}"
|
|
|
|
case "$ext" in
|
|
mod)
|
|
cp "$in" "$out"
|
|
;;
|
|
amod)
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
|
modloopend="$repo/build/tools/modloopend"
|
|
if [[ ! -x $modloopend ]]; then
|
|
echo "joeymod: $modloopend missing; run 'make tools' first" >&2
|
|
exit 2
|
|
fi
|
|
"$modloopend" "$in" "$out"
|
|
;;
|
|
ntp)
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
|
ntp_dir="$repo/toolchains/iigs/ntp"
|
|
if [[ ! -f $ntp_dir/ntpconverter.php ]]; then
|
|
echo "joeymod: $ntp_dir/ntpconverter.php missing; run toolchains/install.sh" >&2
|
|
exit 2
|
|
fi
|
|
if ! command -v php >/dev/null 2>&1; then
|
|
echo "joeymod: php CLI not found; install php-cli" >&2
|
|
exit 2
|
|
fi
|
|
# ntpconverter.php writes <basename>.ntp next to its input. Stage
|
|
# in a scratch dir so we own the output path and don't pollute
|
|
# the caller's source tree.
|
|
tmp=$(mktemp -d -t joeymod.XXXXXX)
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
cp "$in" "$tmp/song.MOD"
|
|
( cd "$ntp_dir" && php ntpconverter.php "$tmp/song.MOD" >/dev/null )
|
|
if [[ ! -f $tmp/song.ntp ]]; then
|
|
echo "joeymod: ntpconverter.php did not produce an .ntp from $in" >&2
|
|
exit 2
|
|
fi
|
|
cp "$tmp/song.ntp" "$out"
|
|
;;
|
|
*)
|
|
echo "joeymod: unknown output extension '.$ext' (expected .mod, .amod, or .ntp)" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
printf 'joeymod: %s -> %s (%d bytes)\n' "$in" "$out" "$(stat -c %s "$out")"
|