367 lines
12 KiB
Bash
367 lines
12 KiB
Bash
#!/bin/sh
|
|
|
|
# Launcher script to work around limitations in vgmplay:
|
|
# OSS only - detects oss wrapper and allows explicit selection
|
|
# Config must be in working dir - automatically cd/mktemps as needed
|
|
# Can't open release packs - plays from temporary directories
|
|
#
|
|
# Original script by ZekeSulastin
|
|
# 7z support by Valley Bell
|
|
|
|
trap '[ -n "$_tmpdir" ] && rm -rf "$_tmpdir"; [ -w "$_log_path/vgmplay.ini" ] && rm "$_log_path/vgmplay.ini"' EXIT
|
|
trap '[ -n "$_tmpdir" ] && rm -rf "$_tmpdir"; [ -w "$_log_path/vgmplay.ini" ] && rm "$_log_path/vgmplay.ini"; reset' HUP INT QUIT TERM SEGV
|
|
|
|
_set_output=
|
|
_output=
|
|
_pulse_server=
|
|
_log_path=
|
|
_binary=
|
|
_config=
|
|
_unpacker=
|
|
_pwd="$(pwd)"
|
|
_host="$(hostname)"
|
|
_ext=
|
|
_unpacker=
|
|
_tmpdir=
|
|
_music_file=
|
|
_m3u_stub=
|
|
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS:-/etc/xdg}"
|
|
_padsp="$(command -v padsp 2>/dev/null)"
|
|
_aoss="$(command -v aoss 2>/dev/null)"
|
|
|
|
_help () {
|
|
cat <<EOF
|
|
Usage: vgm-player [options] filename
|
|
Uses vgmplay to play vgm, vgz, cmf, dro, m3u, and zip'd vgm packs.
|
|
|
|
Options:
|
|
--help display this help and exit
|
|
--version display vgmplay and vgm format versions and exit
|
|
|
|
-a, --alsa force use of aoss (ALSA's OSS wrapper)
|
|
-o, --oss force use of OSS (native OSS, OSSProxy)
|
|
-p, --pulse force use of padsp (PulseAudio's OSS wrapper)
|
|
-s <server>,
|
|
--pulse-server=<server>
|
|
set alternate PulseAudio server (implies --padsp)
|
|
-l, --log outputs to wav files in current directory
|
|
--log-path=<path> outputs to wav files in <path> (implies --log)
|
|
|
|
WARNING: If you plan to log using this script, use --log or --log-path!
|
|
Do NOT set logging on in a custom config, else the script logic will
|
|
remove your logs!
|
|
|
|
--binary=<binary> use alternate vgmplay binary
|
|
--config=<config> use alternate configuration file
|
|
|
|
Keys (In-Player):
|
|
Left/Right seek 5 seconds backward/forward
|
|
Ctrl + Left/Right seek 60 seconds backward/forward
|
|
Space pause
|
|
Escape (twice) or Q quit program
|
|
F fade out current track
|
|
R restart current track
|
|
PageUp or B previous track in playlist
|
|
PageDown or N next track in playlist
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
_to_stderr () {
|
|
echo "$0: $2" 1>&2
|
|
exit $1
|
|
}
|
|
|
|
_die () {
|
|
case $1 in
|
|
too_many_outputs )
|
|
_to_stderr 64 "can only force one output type" ;;
|
|
no_pulse_server )
|
|
_to_stderr 64 "--pulse-server requires server parameter" ;;
|
|
no_log_path )
|
|
_to_stderr 64 "--log-to requires path parameter" ;;
|
|
unknown_option )
|
|
_to_stderr 64 "unrecognized option '$2'\nTry 'vgm-player --help' for more information." ;;
|
|
no_aoss )
|
|
_to_stderr 69 "alsa output forced but aoss not found" ;;
|
|
no_oss )
|
|
_to_stderr 74 "oss output forced but /dev/dsp unwritable or not present" ;;
|
|
no_pulse )
|
|
_to_stderr 69 "pulse output forced but padsp not found" ;;
|
|
too_many_files )
|
|
_to_stderr 64 "only one music file should be specified" ;;
|
|
file_unreadable )
|
|
_to_stderr 66 "unable to read specified input - does it exist?" ;;
|
|
invalid_format )
|
|
_to_stderr 66 "format unsupported" ;;
|
|
invalid_binary )
|
|
_to_stderr 69 "invalid binary specified" ;;
|
|
no_binary )
|
|
_to_stderr 64 "--binary requires binary parameter" ;;
|
|
no_config )
|
|
_to_stderr 64 "--config requires config parameter" ;;
|
|
noread_config )
|
|
_to_stderr 69 "specified config unreadable - does it exist?" ;;
|
|
invalid_config )
|
|
_to_stderr 64 "invalid config specified" ;;
|
|
vgmplay_not_found )
|
|
_to_stderr 69 "vgmplay binary not found" ;;
|
|
no_unpacker )
|
|
_to_stderr 69 "no suitable unpacker found" ;;
|
|
tmpdir_failed )
|
|
_to_stderr 70 "unable to create/use temporary working directory" ;;
|
|
no_output )
|
|
_to_stderr 69 "no usable otuput detected" ;;
|
|
log_path_nowrite )
|
|
_to_stderr 73 "log path unwriteable" ;;
|
|
esac
|
|
}
|
|
|
|
_set_output () {
|
|
if [ -n "$_set_output" ] && [ "$1" != "$_set_output" ]; then
|
|
_die too_many_outputs
|
|
fi
|
|
_set_output=$1
|
|
|
|
case "$_set_output" in
|
|
alsa )
|
|
[ -x "$_aoss" ] || _die no_aoss ;;
|
|
oss )
|
|
[ -w /dev/dsp ] || _die no_oss ;;
|
|
pulse )
|
|
[ -n "$_padsp" ] || _die no_pulse ;;
|
|
* )
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Set terminal title for xterm/rxvt
|
|
case $TERM in
|
|
xterm* | rxvt* )
|
|
printf '%b\n' '\033]2;VGM Player\007' ;;
|
|
* )
|
|
;;
|
|
esac
|
|
|
|
# Parse command line options
|
|
# All single-letter options are exclusive
|
|
while :; do
|
|
case $1 in
|
|
--help )
|
|
_help ;;
|
|
--version )
|
|
echo "VGMPlay 0.40.3 supporting VGM 1.70"
|
|
exit 0 ;;
|
|
-a | --alsa )
|
|
_set_output alsa
|
|
shift ;;
|
|
-o | --oss )
|
|
_set_output oss
|
|
shift ;;
|
|
-p | --pulse )
|
|
_set_output pulse
|
|
shift ;;
|
|
--pulse-server=* )
|
|
_set_output pulse
|
|
_pulse_server="${1#*=}"
|
|
[ -n "$_pulse_server" ] || _die no_pulse_server
|
|
shift ;;
|
|
-s* )
|
|
_set_output pulse
|
|
_pulse_server="${1#-s}"
|
|
if [ -z "$_pulse_server" ]; then
|
|
_pulse_server="$2"
|
|
shift
|
|
fi
|
|
[ -n "$_pulse_server" ] || _die no_pulse_server
|
|
shift ;;
|
|
-l | --log )
|
|
_set_output log
|
|
_log_path="$_pwd"
|
|
shift ;;
|
|
--log-path=* )
|
|
_set_output log
|
|
_log_path="${1#*=}"
|
|
[ -d "$_log_path" ] || _die no_log_path
|
|
shift ;;
|
|
--config=* )
|
|
_config="${1#*=}"
|
|
[ -n "$_config" ] || _die no_binary
|
|
[ -r "$_config" ] || _die noread_config
|
|
file "$_config" | grep -q "ASCII" || _die invalid_config
|
|
shift ;;
|
|
--binary=* )
|
|
_binary="${1#*=}"
|
|
[ -n "$_binary"] || _die no_binary
|
|
if [ ! -x "$_binary" ] || [ ! "${binary##*/}" = "vgmplay" ]; then
|
|
die _invalid_binary
|
|
fi
|
|
shift ;;
|
|
-* )
|
|
_die unknown_option "$1" ;;
|
|
-- )
|
|
shift ;;
|
|
"" )
|
|
_die no_music_file ;;
|
|
* )
|
|
[ -z "$2" ] || _die too_many_files
|
|
_ext="$(echo ${1##*.} | tr [:upper:] [:lower:])"
|
|
case $_ext in
|
|
vgm | vgz | cmf | dro | m3u | zip | 7z | vgm7z )
|
|
[ -r "$1" ] || _die file_unreadable
|
|
_music_file="$1";;
|
|
* )
|
|
_die invalid_format
|
|
esac
|
|
case $_music_file in
|
|
~* | /* )
|
|
break ;;
|
|
* )
|
|
_music_file="$_pwd/$_music_file" ;;
|
|
esac
|
|
break ;;
|
|
esac
|
|
done
|
|
|
|
# Does `vgmplay` exist if --binary not specified?
|
|
# Prefers vgmplay in working dir over any others
|
|
if [ -n "$_binary" ]; then
|
|
break
|
|
elif [ -x "$_pwd/vgmplay" ]; then
|
|
_binary="$_pwd/vgmplay"
|
|
else
|
|
_binary="$(command -v vgmplay 2>/dev/null)"
|
|
fi
|
|
[ -n "$_binary" ] || _die vgmplay_not_found
|
|
|
|
# If a compressed pack, does a suitable unpacker exist?
|
|
case $_ext in
|
|
zip )
|
|
command -v unzip 2>/dev/null || _die no_unpacker ;;
|
|
7z | vgm7z )
|
|
command -v 7z 2>/dev/null || _die no_unpacker ;;
|
|
vgm | vgz | cmf | dro | m3u )
|
|
break ;;
|
|
* )
|
|
_die invalid_format ;;
|
|
esac
|
|
|
|
# Select config
|
|
if [ -r "$_config" ]; then
|
|
break
|
|
else
|
|
for i in "$_pwd" "$XDG_CONFIG_HOME/vgmplay" "$HOME/.config/vgmplay" "$XDG_CONFIG_DIRS/vgmplay" "/etc/xdg/vgmplay" "/usr/local/share/vgmplay" "/usr/share/vgmplay"; do
|
|
_config="$i/vgmplay.ini"
|
|
[ -r "$_config" ] && break
|
|
done
|
|
fi
|
|
# vgmplay will function without a config, but will warn the user thus from inside the program
|
|
|
|
# Make temporary working directory for vgmplay
|
|
# Logdir availability checked here ...
|
|
# Uses $XDG_RUNTIME_DIR, $TMPDIR, /tmp
|
|
# Uses mktemp program for my sanity's sake
|
|
# Assumes user isn't going to try to log into a directory w/ a preexisting vgmplay.ini
|
|
# Seriously, if you're going to do that why would you use this helper to start with
|
|
if [ -d "$_log_path" ]; then
|
|
command sed "s/^LogSound.*/LogSound = 1/" < "$_config" > "$_log_path/vgmplay.ini" || _die log_path_nowrite
|
|
elif [ -n "$XDG_RUNTIME_DIR" ]; then
|
|
_tmpdir="$(command mktemp -d --tmpdir="$XDG_RUNTIME_DIR")" || _die tmpdir_fail
|
|
command cp "$_config" "$_tmpdir/vgmplay.ini" || _die tmpdir_fail
|
|
else #mktemp defaults to tmpdir then /tmp!
|
|
_tmpdir="$(command mktemp -d)" || _die tmpdir_fail
|
|
command cp "$_config" "$_tmpdir/vgmplay.ini" || _die tmpdir_fail
|
|
fi
|
|
|
|
# Determine output to use if not forced
|
|
# Also sets pulse-server if detected
|
|
# PULSE_SERVER, oss, padsp, aoss, log set, error
|
|
if [ -n $_set_output ]; then
|
|
if [ -n "$PULSE_SERVER" ] && [ -x "$_padsp" ]; then
|
|
_set_output="pulse-server"
|
|
elif [ -w /dev/dsp ]; then
|
|
_set_output="oss"
|
|
elif [ -x "$_padsp" ] && command pulseaudio --check ; then
|
|
_set_output="pulse"
|
|
elif [ -x "$_aoss" ]; then
|
|
_set_output="alsa"
|
|
elif [ -n "$_log_path" ]; then
|
|
_set_output="log"
|
|
else
|
|
_die no_output
|
|
fi
|
|
fi
|
|
[ -n "$_pulse_server" ] && _set_output=pulse-server
|
|
|
|
# Extract packs to tmpdir.
|
|
if [ $_ext = "zip" ]; then
|
|
if [ "$_set_output" = log ]; then
|
|
( [ -d "$_log_path" ] && cd "$_log_path" || _die log_path_nowrite
|
|
command unzip "$_music_file" >"$_log_path/extractlog"
|
|
)
|
|
_m3u_stub="$(command grep < "$_log_path/extractlog" m3u | command sed 's/ inflating: \| extracting: //g')"
|
|
_music_file="$_log_path/${_m3u_stub%% }"
|
|
command rm "$_log_path/extractlog"
|
|
else
|
|
( [ -d "$_tmpdir" ] && cd "$_tmpdir" || _die tmpdir_failed
|
|
command unzip "$_music_file" >"$_tmpdir/extractlog"
|
|
)
|
|
_m3u_stub="$(command grep < "$_tmpdir/extractlog" m3u | command sed 's/ inflating: \| extracting: //g')"
|
|
_music_file="$_tmpdir/${_m3u_stub%% }"
|
|
fi
|
|
elif [ $_ext = "7z" ] || [ $_ext = "vgm7z" ]; then
|
|
if [ "$_set_output" = log ]; then
|
|
( [ -d "$_log_path" ] && cd "$_log_path" || _die log_path_nowrite
|
|
command 7z x "$_music_file" >"$_log_path/extractlog"
|
|
)
|
|
_m3u_stub="$(command grep < "$_log_path/extractlog" m3u | command sed 's/Extracting //g')"
|
|
_music_file="$_log_path/${_m3u_stub%% }"
|
|
command rm "$_log_path/extractlog"
|
|
else
|
|
( [ -d "$_tmpdir" ] && cd "$_tmpdir" || _die tmpdir_failed
|
|
command 7z x "$_music_file" >"$_tmpdir/extractlog"
|
|
)
|
|
_m3u_stub="$(command grep < "$_tmpdir/extractlog" m3u | command sed 's/Extracting //g')"
|
|
_music_file="${_m3u_stub%% }"
|
|
#echo "Test:$_music_file|"
|
|
if [ "$_music_file" == "" ]; then
|
|
_music_file="List.m3u"
|
|
#echo "Test:$_music_file|"
|
|
command grep < "$_tmpdir/extractlog" vgm | command sed 's/Extracting //g' >"$_tmpdir/$_music_file"
|
|
#exec cat "$_music_file"
|
|
fi
|
|
_music_file="$_tmpdir/$_music_file"
|
|
fi
|
|
fi
|
|
_music_file=`echo "$_music_file" | sed -e "s/\\s*$//g"`
|
|
|
|
# Plays back song with specified everything
|
|
case $_set_output in
|
|
log )
|
|
( cd "$_log_path"
|
|
"$_binary" "$_music_file"
|
|
)
|
|
command mv "${_music_file%/*}/"*.wav "${_log_path}"
|
|
[ -n "$_music_stub" ] && rm -rf "$_log_path/$_music_stub" ;;
|
|
pulse-server )
|
|
_pulse_server="${_pulse_server:-$PULSE_SERVER}"
|
|
( cd "$_tmpdir"
|
|
exec "$_padsp" -s "$_pulse_server" -n "VGM Player" -m "OSS Emulation (from $_host)" "$_binary" "$_music_file"
|
|
) ;;
|
|
pulse )
|
|
( cd "$_tmpdir"
|
|
exec "$_padsp" -n "VGM Player" -m "OSS Emulation" "$_binary" "$_music_file"
|
|
) ;;
|
|
alsa )
|
|
( cd "$_tmpdir"
|
|
exec "$_aoss" "$_binary" "$_music_file"
|
|
) ;;
|
|
oss )
|
|
( cd "$_tmpdir"
|
|
exec "$_binary" "$_music_file"
|
|
) ;;
|
|
esac
|
|
#read waitvar
|
|
# vim:ts=4:sw=4:et
|