This is my attempt at writing a sound effect driver that's natively compatible with GBDK-2020 (Instead of having to use register values or converting other assembly drivers to GBDK-2020), made to be used with the FX Hammer editor (See hammered.gb
and hammered.sav
). It's aimed at people who want good sounding sound effects but don't wanna have to do custom solutions, feel free to use the translated example SFX's too (see here).
If you've never used FX-Hammer, you can read my guide on using the editor here.
Check out the demo cart to get a taste of it!
- Usage
- For music driver users
- Pros of this driver
- Cons
- C array format
- Games that use CBT-FX
- Many many a thank
- Copy
cbtfx.h
,cbtfx.c
from theinclude
folder andhammer2cbt.py
to your source. - Create your sound effects first in the before mentioned FX-Hammer (See here).
- Copy your .sav file generated by the editor (
hammered.sav
) to your source directory - Use the
hammer2cbt.py
script to convert your desired effects, it takes a few necessary arguments:
usage: hammer2cbt.py [-h] [--fxammo FXAMMO] [--fxnamelist FXNAMELIST]
[--sgb FX_TAB FX_ID FX_PITCH FX_VOL] [--fxinv] [--fxmono]
fxsav fxnum out
positional arguments:
fxsav FX Hammer .sav file (Normally called 'hammered.sav').
fxnum Index of the desired SFX to export.
out Folder where .c and .h files will be saved.
optional arguments:
-h, --help show this help message and exit
--fxammo FXAMMO Number of SFX to export (starts at fxnum, ends at
fxnum + fxammo)
--fxnamelist FXNAMELIST
Text file with all the names for the SFX, each on one
line (SFX names shouldn't have spaces), you can add 4
values after the SFX name to define SGB sound values
(See --sgb parameter).
--sgb FX_TAB FX_ID FX_PITCH FX_VOL
Add Super Game Boy support.
--fxinv Invert pan values for SFX (FX Hammer has them inverted
by default, without this flag, the panning will be
corrected)
--fxmono Avoid all panning writes and store as mono.
example:
python3 hammer2cbt.py --fxammo 10 hammered.sav 0 include/sfx/
^ Exports SFX's $00-$09 to the sfx folder.
- Include the generated .h files into your desired .c files.
- Add a call to
CBTFX_update
in your main loop so it gets called every frame, or add it as a VBL interrupt (Recommended to avoid stutter). - When you need to play a sound effect, call
CBTFX_init(&your_SFX_name[0])
(There's also a macro generated calledCBTFX_PLAY_your_SFX_name
that should do the same thing.).
This repository comes with an example project and all the sound effects from FX-Hammer converted and an example on hUGEDriver integration (See src
).
If you're already using a driver for music such as hUGEdriver, you will need to add a few lines of code to the CBTFX functions to make it play ball with this.
There's 4 macros in cbtfx.c
that should be set to the music driver's mute functions, the before mentioned drivers have a single function that toggles channels, in that case you should set them like:
// For hUGEdriver
#define MUSIC_DRIVER_CH2_ON hUGE_mute_channel(HT_CH2, 0);
#define MUSIC_DRIVER_CH2_OFF hUGE_mute_channel(HT_CH2, 1);
#define MUSIC_DRIVER_CH4_ON hUGE_mute_channel(HT_CH4, 0);
#define MUSIC_DRIVER_CH4_OFF hUGE_mute_channel(HT_CH4, 1);
There is also a flag for mono music, if your song doesn't modify panning (Register NR51) at all but your effects do, set it to 1, this will reset the panning after the effect is played to avoid parts of the song being off-panned after an effect.
// If your music does modify NR51:
#define MONO_MUSIC 0
ALSO remember to update CBTFX after your music driver, to avoid the music driver going over the sound effects.
- Works with GBDK-2020 out of the box, easy to tweak and understand.
- Super Game Boy support.
- SFX's are 1:1 to FX Hammer's playback.
- SFX are fairly small in output size, every SFX step takes up 7 bytes at most, with one-channel SFX going from 2 to 5 bytes per step and Super Game Boy support taking up only 5 extra bytes on the header. All 10 default SFX on the demo cart only take up a few bytes over 1K of ROM, with SGB support and panning! Without those, they can go as low as 989 bytes.
- Driver/SFX data isn't designed for bank switching out of the box, my personal understanding of bank switching with GBDK is small so if anyone would like to add that feature, it'd be great.
- Only one sfx at a time.
This is a chopped down version of my first attempt at this driver, with still a few bits to save, but mostly small:
Header:
Offset Description
====== ==========================
00 Channels used + SFX priority
0 0 0 0 0000
| | | | | |
| | | | |__|___ Priority (0-15)
| | | |
| | | |________ Unused for now
| | |
| | |__________ CH4 used flag
| |
| |____________ SGB support flag
|
|______________ CH2 used flag
01 SFX length in steps
-- Only written if SFX uses SGB --
02 SGB command (65)
03 Sound Effect A ID
04 Sound Effect B ID
05 Sound Effect attributes (See Pandocs)
06 Music score code (Always 0)
----------------------------------
Step(s):
Offset Description
====== ==========================
00 Step length in frames (7th bit says if there should be a new NR51 write)
-- Only written if new panning was set --
01 Frame pan (Directly written to NR51, only stored if the length frame's 7 bit is high)
-----------------------------------------
-- Only written if SFX uses CH2 --
02 CH2 Duty (Directly written to NR21)
----------------------------------
03 Frame volume (bits 7-4 = CH2 volume, bits 3-0 = CH4 volume)
-- Only written if SFX uses CH2 --
04 CH2 Frequency (Lower 8 bits from 11 bit frequency, Directly written to NR23)
05 CH2 Frequency (Higher 3 bits from 11 bit frequency, Directly written to NR24)
----------------------------------
-- Only written if SFX uses CH4 --
06 CH4 Frequency (Directly written to NR43)
----------------------------------
- Aleksi Eeben for creating Carillon and FX Hammer and allowing me to host the FX-Hammer editor in this repo.
- ZestyDev for giving me some ideas on what to update on the driver + energy to do it
- bbbbbr for getting my code to work at first and helping me out with other code related shenanigans
- SuperDisk for helping me out with some hUGE related stuff