Terrific Audio Driver v0.3.0
Introducing version 0.3.0 of the Terrific Audio Driver.
This version does not add new features, instead I made 2 major back end changes: The audio driver has been ported to spc-700 assembly and tad-gui now uses the cpal crate to play audio.
The new release can be downloaded from GitHub.
The driver has been ported to spc-700 assembly
I have rewritten the audio driver in assembly using a custom assembler written in rust.
This was done for 4 major reasons:
-
Simplify TAD compilation. TAD required you to import the wiz git submodule and compile wiz before
cargo buildto embed the audio driver in the compiler and GUI. I've had to help a few people navigate TAD compilation on Discord. Now, the rust build script uses my new assembler to directly build the audio driver. -
The build script now has access to all symbols, constants and labels. The rust code can extract things like a
BYTECODE_VERSIONconstant out of the audio driver and emit a compile-time assert error if it doesn't match aBYTECODE_VERSIONconstant in the bytecode module. -
It enables a few optimisations I could not implement in wiz:
- Wiz does not allow a label to escape a
{}scope. - Wiz cannot emit the
bbcbranch if bit clear norbbsbranch if bit set instructions.
- Wiz does not allow a label to escape a
-
I can add static
.assertstatements to the audio driver.
Why did I write the audio driver in wiz to begin with? I was using wiz in unnamed-snes-game, loved the language and decided unnamed-snes-game's audio driver will also be written in wiz. Having type checking on variable accesses and forward-referenced inlines greatly sped up development of the audio driver.
Now that the audio driver has matured and the audio driver has excellent test coverage1. The TAD compilation issue was getting more annoying. I did not want to commit the audio driver binary to my git repository, nor did I want the build script to download the audio-driver binary from somebody else's computer. Spending a month writing my own assembler sounded like a nice side project.
Once I realised I do not need namespaces, macros or substitutions (think
.IDENT(.SPRINTF(..)) in ca65 or {} in bass) the design became a lot simpler
and development greatly sped up. The only complex feature my assembler
supports is forward-referenced inline procedures. Keeping the vibrato and
portamento effects code next to each other in the source file (despite them
being 325 bytes apart in the binary) was well worth it.
Porting the audio driver to assembly involved renaming the .wiz files to
.asm and manually fixing the 2331 assembler errors.
A lot of the lines were converted using regular expressions. The remaining
lines, which were mostly control flow and arithmetic, were manually ported by
hand over the course of a few days.
Once the assembler stopped emitting errors, I used hexdump and delta (a
colourized diff) to find and manually fix all of times the assembly port was
not byte-identical to the wiz audio-driver. I encountered: wrong branch
instructions, missing index register typos, wrong operand order in multiple
mov instructions, a few missing # (immediate) in the arithmetic
instructions, missing clrc instructions and 4 bugs in my assembler.
This was a nice side project. I'm leaving the audio-driver byte-identical for this release. The next release will include many small optimisations I noticed while I was porting the audio-driver to assembly.
tad-gui now uses cpal to play audio
The other pain point when compiling TAD is the SDL dependency. When I wrote
tad-gui I used sdl2 crate to handle audio in a simple and cross platform
manner. While the sdl2 crate is easy to compile on Linux, setting up the
SDL2.0 development libraries on Windows is a bit complicated.
I've replaced the sdl2 dependency with the cpal
crate. This involved writing my own resampling ring buffer that converts the
audio driver's 32040Hz sampling rate to a 48000Hz sampling rate that most
computers expect.
Linux and BSD users will need to install the ALSA development libraries
(libasound2-dev on Debian or alsa-lib-devel on Fedora) to compile this
latest release.
There are no new dependencies when compiling TAD on windows.
What's Next
Here's what I have planned for the next two releases of the Terrific Audio Driver:
- Implement those optimisations I can now implement in spc700 assembly.
- Improve MML command merging.
- Redesign the samples tab and improve the samples UX.
- Design the data formats, IO communications protocol and UX needed for sample swapping.
I'm also going to restart development in Space Rescue Squad.
-
test_bc_interpreterruns TAD songs through an emulated audio driver and a rust bytecode interpreter and verifies that the audio-driver variables and bytecode interpreter state is identical. ↩