Hooked on Amstrad Chiptunes - Volume 1 - Dave Rogers
Experience the glory of some of the most revered 80's CPC/ZX chiptunes from the comfort of your PICO-8 console!
- Cybernoid 2: The Revenge
- Stormlord 2: Deliverance
- Battle Valley
- Turbo Boat Simulator
right arrow - next song
left arrow - previous song
This cart emulates the Amstrad CPC/ZX Spectrum AY-3-8910 audio chip to output chiptunes to PICO-8's 5512Hz 8-bit mono PCM serial buffer. To feed the emulation it contains a sound driver capable of generating AY register inputs across three channels of tone/volume/noise-enable as well as a single shared noise tone.
The sound driver was derived from 13 different CPC games and one ZX game. All these games had their music composed or converted/arranged by (the legendary, in my opinion) J Dave Rogers, who also wrote the sound driver code for the games as was customary for chiptune musicians in the 80's. This common lineage made it reasonable to reverse engineer the Z80 code and generalize the driver to handle all the games' music.
I think it sounds a little better in native PICO-8 rather than on the web player. Understand however that in the CPC the AY chip was clocked at 1,000,000Hz (and 1,773,447Hz on the ZX), and emulators typically default to sample at 44,100Hz. Whereas PICO-8 ticks at 60Hz and the serial buffer samples at 5512Hz. Only so much can be done - the percussion/noise is especially vulnerable to low sampling rates.
The AY emulation code is augmented to support the waveform visualization by tracking zero-crossings - this extra work can be removed if the goal is pure audio.
Without the graphics, the sound driver + AY emulator runs at a consistent 24-25% of frametime on a 60hz cart. This demonstrates that, for the appropriate PICO-8 game, it's reasonable to completely emulate the music and sfx via the serial buffer. Alternatively the sound driver portion could be used to drive PICO-8's sfx/music buffers in real time which would allow a lot more music in the cart with full audio sample rate quality. Or do both and synchronize native sfx/music with generated serial buffer output.
The game logos were compressed with PX9
Fixed credits for Herobotix and Battle Valley, and fixed percussion on initial part of Zynaps - thanks to feedback from Dave Rogers!
Each song has 3 color gradients. One for normal pitch+volume-enveloped notes, one for volume-only-enveloped trills (rapidly alternating between two pitches - a handy technique when you only have three channels!), and one for noise-enabled notes. Different songs have different colors. The sound driver could indeed use different colors for different pitch/volume/noise-tone envelope combinations (instruments) but three gradients of 5 colors already used 15 of the available 16 colors. :)
@freds72 there's a little present for you in the code. You'll know it when you see it. ;)
Most of the emulation perf hit occurs because it has do be done for every sample, and at 5512Hz there are about 90 samples required every _update60 frame. Currently it's using 25% of the frametime, mostly on the AY emulation. So if SID can be done in less than four times that effort it should work (but with less intensive visuals).
My instinct is that it would be too perf prohibitive to use in a game. But maybe if your tune only needed one channel/voice with all the SID bells and whistles, and other channels are simpler or done through native PICO-8 music/sfx then it could still sound pretty interesting.
Someone would have to try it to be sure!
Standard .SID files are chunks of 6510 code, so you'd need to write an emulator for that as well (or get some kind of log of SID register writes instead).
EDIT: Oh, hang on, .ay files are the same thing, I thought they were more of a register-log thing. I'm thinking of .vgm, which is a log - which raises possibilities...
@Two_Owls yep a register log would work too. I agree emulating the z80/6502 CPU will be too burdensome for PICO-8. However unless the register log has phenomenal compression it's likely to need more data than re-implementing the sound driver (which sets the register values) in lua.
For example this cart re-implements the sound driver, and here are the sizes in bytes for the runtime chiptune data:
audio: path='cpc/netherworld.sna' size=1525
audio: path='cpc/zynaps.sna' size=1117
audio: path='cpc/uridium.sna' size=910
audio: path='cpc/cybernoid.sna' size=1419
audio: path='cpc/cybernoid2.sna' size=1098
audio: path='cpc/nebulus.sna' size=1108
audio: path='cpc/marauder.sna' size=1210
audio: path='cpc/stormlord.sna' size=1275
audio: path='cpc/stormlord2.sna' size=1311
audio: path='cpc/anarchy.sna' size=911
audio: path='cpc/battlevalley.sna' size=1676
audio: path='cpc/herobotix.sna' size=782
audio: path='cpc/turboboat.sna' size=1574
audio: path='zx/bearagrudge.z80' size=1427
They're a little bigger than they need to be right now, and they're not compressed.
The sound driver sets up to 3x 16-bit periods, 3x 4-bit volumes, 3x 1-bit flags, and 1x 8-bit noise period. So about 8.875 bytes at 50hz for most songs, i.e. 443.75 bytes of register values per second of music (before compression). Most songs are a couple minutes long, so about 53KB per song. I'm sure they would compress very well though. Certainly worth a try - it is a lot easier to capture a register log than reverse engineer assembly language sound drivers!
[Please log in to post a comment]