USBSID-Player is a Cycle Exact Commodore64 emulating PSID/RSID & PRG tune player for command line, websites and embedding that is aimed for use with USBSID-Pico. USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board for interfacing one or two MOS SID chips and/or hardware SID emulators over (WEB)USB with your computer, phone or ASID supporting player.
- Cycle exact C64 emulation (CPU, CIA1/2, VIC and up to 15 SID chips, the
multiSidConfiglimit of a v5 tune), the same core for every target below - Plays PSID, RSID and PRG/P00 (tunes skip the boot, programs boot to BASIC and RUN/SYS themselves)
- Four output backends (
SidBackend): a real USBSID-Pico over USB, software audio (ResidFp) via miniaudio, a WAV file or a Network SID Device server (v4/v5) over TCP - Software audio and netdevice play up to 15 SID chips, a real board (USB, WebUSB or embedded) plays the first 4 sockets
--stereopans a multi-SID tune per the v5 panning hint (software audio and WAV only, off by default)- FM/OPL playback via Nuked-OPL3-fast for tunes that use the FM/OPL chip of a board
- Netdevice sends FM OPL as NSD v5
TRY_WRITE_EXwrites to$DF40(address) and$DF50(data),TRY_SET_FM_OPLenables/disables FM OPL on the server - HVSC Songlengths support, a tune stops when the song ends (a v5 tune uses its embedded song length table when the database has no entry)
- Muting and solo by chip and voice, subtune switching, PAL/NTSC forcing and a
--tracemode that records SID register events to a file - Logging switches per subsystem (SID/CIA/VIC/CPU reads and writes, banking, instructions, timers) like the old player
- Embeds into the USBSID-Pico firmware (
ONBOARD_SIDPLAYER=1, RP2350 only, needs-O3), a drop in replacement for the old player - Compiles to WebAssembly for the browser, drives a board over WebUSB (cycle exact) or ASID over Web MIDI (a snapshot per frame), the AudioWorklet worker keeps playing in a background tab
Output nsd and --net-* options are only available on Linux and MacOs.
usage: usplayer [options] <file.sid|file.prg|file.p00>
a SID file plays; a program is loaded where it says and started the
way you would start it, with RUN or with SYS
-s, --song N start at subtune N (default: the tune's own), plays on
into the following songs unless --single
-1, --single play only this song, stop when it ends
-t, --seconds N stop after N seconds (default: play until ctrl-c)
-i, --info print what the file says and exit
-n, --no-device run without hardware, useful for checking a tune
--no-roms run on the stub KERNAL, without BASIC and character
ROM, the way a build without ROMs does
--detach with --output=onboard: send, start and exit, the
tune keeps playing on the board
--board-stop, --board-pause,
--board-next, --board-prev
send that command to the board's own player and
exit, no file needed
sound:
-o, --output M usbsid (default), asid, nsd, audio, wav or onboard.
usplayer falls back to audio when no board is found.
onboard uploads the tune to the board's own player
(_em firmware, one board, file or - for stdin, at
most 65535 bytes) and follows it with the same
keys; --boards takes one serial or index there, and
-T -S -ms -ss -fa -w are refused
-lb, --list-boards
list every attached board's serial number and exit
-b, --boards SPEC
open these boards for --output=usbsid instead of
the one the driver picks, in this order (board 1
is the first, etc.). SPEC is a comma separated list
of serial numbers from --list-boards, for example
AB12,CD34 opens AB12 as board 1 and CD34 as board 2
regardless of USB-connect order, and leaves any
other attached board untouched. The tune's SIDs are
spread across every opened board's SIDs, board 1's
first. (default: one board, the first in USB
bus/port order)
-lm, --list-midi list every available midi output device
-a, --asid N Midi supporting ASID port to use for --output=asid
(default is 0)
-nh, --net-host H Network SID Device server to connect to for
--output=nsd (default 127.0.0.1)
-np, --net-port P its TCP port (default 6581)
-ns, --net-sids N SIDs to tell it about (default: the tune's own count)
-w, --wav FILE write a WAV instead of playing, implies --output=wav.
A tune with more songs records from the start song
through the last, use -1/--single (or -t) for one
song. With -nsl and no -t the WAV never ends
-ra, --rate N sample rate for audio and wav (default 44100). A device
may impose its own, which is then what is used
-q, --quality Q fast (linear) or good (sinc, default)
-st, --stereo pan multi-SID tunes per the v5 file's own hint
(--output=audio/wav only; off by default, one channel)
-rv, --resid-volume N
reSIDfp (SID) output level, percent, 0-300
(--output=audio/wav only; default 100)
-fv, --fmopl-volume N
FM/OPL output level, percent, 0-300 (same scope;
default 50 - the OPL is the louder of the two chips)
-T, --trace FILE write every SID register event to FILE, laid out like
-srw (chip, C64 address, register:value, [C] cycle
delta) plus the running cycle total and the play
time MM:SS.mmm. Records what is played, also works
with a board and with --wav; add -n for a silent
run that only records
-m, --mute SPEC silence voices (gate/sustain forced off; everything
else for that voice still reaches the backend). SPEC
is a comma separated list of CHIP:VOICE or CHIP for
all three, chips and voices counting from 1, for
example 1:3 or 2 or 1:1,1:2
-S, --solo SPEC the other way round, and harder: only SPEC's writes
reach the backend, everything else is dropped before
it gets there (and before -srw sees it), not just
silenced. --solo 1:2 --wav v2.wav records voice two
on its own with no other chip/voice traffic
-ms, --mute-solo SPEC
the old --solo: silence everything except SPEC
the soft way, same as --mute. Kept under its own name
for anyone relying on that behavior specifically
-P, --pal force PAL timing
-N, --ntsc force NTSC timing
hardware:
-rr read the SID back from the chip, not the mirror
-f force everything into socket two
-fa XX force everything to physical base $XX (hex)
-ss, --select-sids SPEC
play only these of the tune's SIDs, on the
board's sockets in the order given. SPEC is a comma
separated list of tune SID numbers counting from 1,
each optionally followed by :SLOT to name the exact
socket it lands on, also counting from 1. For
example 3,4,5 puts the tune's 3rd SID on the board's
first socket, its 4th on the second, and its 5th on
the third; 3:1,5:4 instead puts the 3rd SID on the
first socket and the 5th on the fourth, leaving the
second and third empty. A bare entry claims the
lowest socket no :SLOT entry already claimed. At
most 4 sockets are used on one board, or every
SID of the boards --boards opened. fm or fm:SLOT
puts the tune's FM/OPL on that socket, only when
it is the board's configured FM/OPL; with SPEC
given, an FM/OPL not named this way is not played
(--output=usbsid only; default: the tune's first N
SIDs on the first N sockets, in order)
-oh, --overhead N Cycles one hardware access costs (default 1; 0 for
netdevice software servers)
-sl, --songlengths F
HVSC Songlengths database, to stop when the song
ends. Found by itself in $SONGLENGTHS,
~/Songlengths.md5, $HVSCROOT or $HVSC_BASE
DOCUMENTS/Songlengths.md5, or $HVSCDB.
-nsl, --no-songlengths
ignore it even when one is found
logging, to stdout, same switches as old player:
-srw SID reads and writes
-sidr / -sidw SID reads or SID writes only
-c1rw / -c2rw CIA1 / CIA2 reads and writes
-vrw / -vrrw VIC register writes / reads
-lrw every CPU read and write
-llrw reads that come out of a ROM
-pla banking changes
-ins every instruction
-tim the timers, once a frame
-lmem the SID registers, once a frame
-h, --help this--output=onboard does not emulate anything on the host. It uploads the tune to the player that runs on the board itself (firmware built with ONBOARD_EMULATOR=1, the _em builds) and follows it: the play time is polled from the board, the same keys work (pause, subtune, restart, fast forward, voice mute) and the song ends by the Songlengths database like the normal player. --detach sends, starts and exits, the tune keeps playing. The --board-stop, --board-pause, --board-next and --board-prev options need no file. - as the file reads the tune from stdin. -s, -1, -t, -f, -m, -b (exactly one board, serial or index from --list-boards), -sl and -nsl apply, -T -S -ms -ss -fa -w are refused.
usplayer -o onboard tune.sid
usplayer -o onboard -s 2 -t 90 -b AB12 tune.sid
usplayer -o onboard --detach tune.sid
usplayer --board-stop
curl -sS https://example.org/tune.sid | usplayer -o onboard -Linux example.
sudo apt install libusb-1.0-0-dev libudev-dev
git clone https://github.com/LouDnl/USBSID-player && \
git clone https://github.com/LouDnl/USBSID-Pico-driver USBSID-player/lib/driver
cd USBSID-Player
cmake -S . -B build_cli \
-DDESKTOP=1 -DEMBEDDED=0 -DWEB=0 -DREQUIRE_AUDIO=1 && \
cmake --build build_cli --parallel $(nproc) && \
cp build_cli/usplayer .Linux example.
./usplayer --song 1 tune.sid # play from a subtune
./usplayer --output wav --wav out.wav tune.sid
./usplayer -s 2 -1 -w song2.wav tune.sid # record subtune 2 only
./usplayer --output nsd --net-host 192.168.1.42 tune.sid # play over a Network SID Device server
./usplayer -i tune.sid # print the tune's own info and exit
./usplayer -h # the full option listNeeds libusb-1.0 + libusb-1.0-0-dev and on Linux libudev + libudev-dev for USB access, found via pkg-config. -dev is for building, the other for running.
Linux example.
Needs the Emscripten SDK (built and tested with emcc 4.0.12):
source /path/to/emsdk/emsdk_env.sh
git clone https://github.com/LouDnl/USBSID-player
cd USBSID-Player
emcmake cmake -S . -B build_web -DWEB=1 && \
cmake --build build_web --parallel $(nproc)
cd web
python3 -m http.server 8000
# http://localhost:8000/web/demo.htmlWebUSB and Web MIDI need a secure context (https:// or http://localhost), see docs/API_WEB.md for the JavaScript API, the transports and how to embed the player in another page.
The firmware pulls this repository in via cmake/usbsid-player.cmake and builds with ONBOARD_SIDPLAYER=1. Use the API with #include <usplayer.h>:
load_sidtune(sidfile, sidfile_size, tuneno);
init_sidplayer();
start_sidplayer(false);
while (playing) loop_sidplayer(); /* one frame per call */
stop_sidplayer();See docs/API_EMBEDDED.md for the full API.
The suite is part of the command line build (BUILD_TESTS defaults to 1), use the same build directory:
cmake -S . -B build_cli \
-DDESKTOP=1 -DEMBEDDED=0 -DWEB=0 -DBUILD_TESTS=1 && \
cmake --build build_cli --target usplayer-test --parallel $(nproc) && \
./build_cli/usplayer-testEvery component has a test_<name> executable registered with CTest, run them all with ctest --test-dir build_cli after a full cmake --build build_cli.
The asid suite (tests/test_asid.cpp, run with ctest -R asid or ./build.sh test for all) checks the ASID SysEx messages against stub RtMidi symbols, no MIDI port needed. It is built when RtMidi is available, else it reports [SKIP].
Uses ymfm as FM/OPL engine. Command line player only (CMake refuses FM_YMFM=1 with WEB=1 or EMBEDDED=1), EXECUTABLE names the binary, the regular usplayer stays untouched:
cmake -S . -B build_ymfm \
-DDESKTOP=1 -DEMBEDDED=0 -DWEB=0 -DREQUIRE_AUDIO=1 \
-DFM_YMFM=1 -DEXECUTABLE=usplayer-ymfm && \
cmake --build build_ymfm --parallel $(nproc) && \
cp build_ymfm/usplayer-ymfm .Embedded player:
- USBSID-Pico firmware ~ supported by boards with a Pico2
Web player:
- USBSID-Pico Web configtool
- HippoPlayer ~ a webbased Amiga emulator
- Deepsid
CLI player:
- USBSID-Configtool ~ in active development
- ResidFp
- miniaudio
- Nuked-OPL3-fast, a bit-exact fork of Nuked-OPL3
- ymfm, optional FM/OPL engine for the
cli-ymfmbuild (CLI only)
USBSID-Player is licensed under the GNU General Public License, version 2 or (at your
option) any later version (GPL-2.0-or-later), see LICENSE. Vendored libraries in
lib/ keep their own licences.
The workings of this player are heavily inspired by and based upon the following fantastic projects: