SatouSynth
SatouSynth is a high-performance VGM playback library written entirely in Common Lisp, based on VGMPlay. The goals are to provide native VGM playback in Common Lisp without bindings to C; a cleaned-up and OOP-ified version of VGMPlay's API as a library; and performance on par with my equivalent Crystal library, YunoSynth.
Wanna support this project? Buy me a coffee on Ko-Fi, or support me through Liberapay.
Example videos
Features
- Rendering of VGM files to PCM.
- High quality resampling.
- Compressed (gzip) VGM loading, as well as a mechanism to extend this with
additional compression methods. New methods include:
- BZip2 compressed VGMs
- ZStandard compressed VGMs.
- Full GD3 tag support.
- DAC support.
Implemented Chips
More chips will be added as time goes on.
- Bandai Wonderswan
- Capcom DL-1425 QSound
- General Instruments AY-1-8910 and derivatives
- Hudson HuC6280 (two different cores)
- Irem GA20
- Konami K051649
- Konami K053260
- Konami K054539
- NEC μPD7759
- Namco C140 / Namco 219 ASIC
- Namco C352
- Nintendo GameBoy (DMG)
- Nintendo NES (APU) and Famicom Disk System
- Nintendo Virtual Boy (VSU-VUE)
- OKI MSM6258
- OKI MSM6295
- Philips SAA1099
- Sega 32x PWM
- Sega MultiPCM
- Sega SegaPCM
- Seta X1-010
- Texas Instruments SN76489 and related
- Yamaha YM2151 (OPM)
- Yamaha YM2203 (OPN)
- Yamaha YM2608 (OPNA)
- Yamaha YM2610 / YM2610B (OPNB)
- Yamaha YM2612
- Yamaha YMZ280B (PCMD8)
Project Goals
The overall goal for SatouSynth is high performance VGM playback with accuracy on par with VGMPlay, while being 100% Common Lisp with no external bindings except ZStandard. SatouSynth will also provide an object-oriented API to access chip emulators and VGM playback. Long term, playback of .s98, GYM, and other similar file formats are overall goals.
The road towards v1.0 essentially prioritizes compatibility with VGMPlay as far as emulator cores and VGM support goes. Additionally, whatever core VGMPlay uses for its default for a particular chip will be ported first. Additional features/cores will probably sneak in as well, but the actual priority for v1.0 is compatibility with VGMPlay. This has been chosen because VGMPlay is the official player for VGM files, and (as far as I'm concerned) the reference implementation for VGM support.
Versions beyond v1.0 will prioritize compatibility with libvgm as far as the selection of emulator cores, VGM support, and any additional file formats go. This is being chosen because libvgm is the successor to VGMPlay.
Development milestones can be found on the wiki. There is also a different wiki page for emulator cores to (possibly) add in the future that are beyond what VGMPlay offers.
Releases
Releases can be found on the wiki.
Usage
API documentation can be found here in PDF format, and here in HTML format
This library only supports SBCL.
Most dependencies can be installed using QuickLisp (though this hasn't been tested). The exception is the CL-SDM library, which must be obtained from here.
Place the SatouSynth code (and the CL-SDM dependency) somewhere where ASDF can find them, then run this in your REPL:
(asdf:load-system :satou)
Example Player
This uses my CL-RemiAudio library
for playback. A slightly expanded version of this code that also prints some
basic GD3 info and handles fadeout is in the example-player.lisp file in the
root of the repository.
(defun play-vgm (filename)
(cl-ra/drivers:with-driver (:ao)
(cl-ra/drivers:with-open-device (out :ao)
(let* ((vgm (satou:load-vgm-file filename))
(player (satou:make-vgm-player vgm))
(buf (sdm:new-array 1024 single-float 0.0)))
;; Start the player, do a quick GC
(satou:vgm-player-play player)
(sdm:gc t)
;; Loop twice if the VGM has loop information.
(loop until (or (and (not (satou:vgm-has-loop-info-p vgm))
(plusp (satou:vgm-player-times-played player)))
(= (satou:vgm-player-times-played player) 2))
do ;; Render then send to the audio output
(satou:vgm-player-render player buf)
(cl-ra/drivers:write-buffer out buf))))))
(play-vgm #P"/path/to/your/song.vgm")
Known Issues
SatouSynth uses the Chipz library to decompress GZipped VGM files. Chipz cannot
be compiled with the compiler set to restrict the SPEED level to 0 (e.g.,
(sb-ext:restrict-compiler-policy 'speed 0 0). This is a limitation if Chipz,
not SatouSynth.
Flags for *FEATURES*
SatouSynth supports a few flags that can be put into *FEATURES* prior to
compiling it.
:SATOU-DEBUG: Print various debug information to the console.:SATOU-SUPER-DEBUG: Print even more debug information to the console.:SATOU-WD40: Enable various micro-optimizations that may possibly do unsafe things in exchange for some small speed boosts.
File Names
In the chips folder, all files should follow this scheme:
chip-[CHIPNAME].lisp: This is the public interface for the chip. Replace[CHIPNAME]with the name of the chip (e.g.chip-ym2151.lisp).emu-[CHIPNAME]-[BASE].lisp: This is the private emulator for the chip. Replace[CHIPNAME]with the name of the chip, and[BASE]with the code that the emulator is based on (e.g.emu-ym2151-mame.lisp).
Style info
I use a slightly unorthodox style for my code. Aside from these differences, please use normal Lisp formatting.
- Keep lines 118 characters or shorter. Obviously sometimes you can't, but please try. Use 115 characters for Markdown files, though.
- I mark types using the form
T/..... For example,T/SOME-NEAT-TYPE. For predicates on these, useSOME-NEAT-TYPE-P. - No tabs. Only spaces.
How do I contribute?
- Go to https://fossil.cyberia9.org/satousynth/ and clone the Fossil repository.
- Create a new branch for your feature.
- Push locally to the new branch.
- Create a bundle with Fossil that contains your changes.
- Get in contact with me via email, Fediverse, or open a ticket.
Contributors
- Remilia Scarlet - creator and maintainer
- Homepage: https://remilia.sdf.org/
- Fediverse: @remilia@social.cyberia9.org
- Email: zremiliaz@postzeoz.jpz My real address does not contain Z's
Links and Licenses
SatouSynth itself is under the GNU Affero General Public License version 3.
The emulation cores, which were all ported by hand to Common Lisp, have various
other licenses, which can be found in the docs/licenses folder in this
repository. Most of them are from the MAME project.
Much of the playback code is indirectly based on heavily modified code from VGMPlay by Valley Bell, et al., and ported by way of YunoSynth.