Sound tutorial
GBDK Sound tutorial
Warning: this is all being typed into Notepad in one go. There will probably be a ton of spelling and grammar errors.
Sound is one of the hardest things to find tutorials and examples on in gameboy development, but after finding some information and a lot of trial and error I finally figured it out.
To get sound to play you just have to write some values to the sound registers. In GBDK the sound registers are defined in "Hardware.h" which is automatically included if you include "gb.h".
Each register has 8 bits, and each bit does something specific for the sound. For example the 4th register in each channel looks like this:
bit | function
7 Initialize (trigger channel start, AKA channel INIT)
6 Consecutive select/length counter enable
5-3 Unused
2-0 3 Most Significant bits of frequency (channels 1,2,3)
In order to write to a specific bit we use a 2 digit hexadecimal number. If you dont know a hexidecimal number is just a diffrent way of counting, like with binary there is only 1s and 0s, and with decimal there is 0,1,2,3,4,5,6,7,8, and 9, with hexidecimal there are 16 different numbers with 10 - 16 represnted by letters.
So counting in hexidecimal would go 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. Each digit in hexidecimal is 4 digits in binary
binary | hexidecimal | decimal
0000 | 0 | 0
0001 | 1 | 1
0010 | 2 | 2
0011 | 3 | 3
0100 | 4 | 4
0101 | 5 | 5
0110 | 6 | 6
0111 | 7 | 7
1000 | 8 | 8
1001 | 9 | 9
1010 | A | 10
1011 | B | 11
1100 | C | 12
1101 | D | 13
1110 | E | 14
1111 | F | 15
So back to our 4th register example, you need the 7th bit to be high. We wont worry about ending the sound yet, so we will leave bit 6 low.
bits 5-3 are unused so we will leave those low (unnecessary high bits drain the batteries faster). That leaves bits 2-0 for your frequency which will be a number between 0-7 where the higher the number the higher the frequency(but I'm still figuring that part out).
If we want a frequency of "5" then we need to write the register with this value: 1000 0101 which equals 0x85 in hexidecimal (hexidecimals are writen with 0x in front of them, couldn't tell you why, it just is that way).
Now we need to write this to the right register, in gbdk the sound registers are NR10 - NR52. The left digit shows the channel, there are only 4 channels. NR50-NR52 are for turning the sound registers on which are off by default to save batteries.
The right digit shows which register in the channel it is. Ill go into more detail about each channel and register later, but for now we are just using register 4 of channel 1.
So to finally write that byte(8 bits) to the register we would put:
NR14_REG = 0x85;
(In gbdk you have to add _REG to the end of the register)
Thats how you write to a register, but that alone will not play sound. Before you can play a sound you have to set NR52, NR51, and NR50 (IN THAT ORDER!).
NR52 turns on the rest of the sound registers by writing 0x80 to it, or turns them off by writing 0x00 to it. Here is what each bit of NR52 does:
7 Master sound circuitry power control (read/write)
6-4 unused
3 Channel 4 status flag (Read-only)
2 Channel 3 status flag (Read-only)
1 Channel 2 status flag (Read-only)
0 Channel 1 status flag (Read-only)
NR51 selects which channels output sound, where 1 is enabled and 0 is disabled. So if you want to output channel 1 you would put 0x11, for channel 2 0x22, for channel 3 0x44, for channel 4 0x88
7 Channel 4 to Main SO2 output level control (Left)
6 Channel 3 to Main SO2 output level control (Left)
5 Channel 2 to Main SO2 output level control (Left)
4 Channel 1 to Main SO2 output level control (Left)
3 Channel 4 to Main SO1 output level control (Right)
2 Channel 3 to Main SO1 output level control (Right)
1 Channel 2 to Main SO1 output level control (Right)
0 Channel 1 to Main SO1 output level control (Right)
NR50 controls volume and something called Vin which I have no clue what does so I just leave that part alone. Max volume is 0x77 and no volume is 0x00.
7 Output Vin to Main SO2 output level control (1: on; 0: off)
6-4 SO2 (Left) Main Output level (volume)
3 Output Vin to Main SO1 output level control (1: on; 0: off)
2-0 SO1 (Right) Main Output level (volume)
After you have set those you can play sound by writing to the registers. Each channel is fairly different, so their registers are not all the same. Channel 1 and 2 are square wave channels (I dont really know what that means yet), these are the main channels.
Channel 1 has a sweep register (NR10) that raises or lowers the pitch each "tick" so you can make nice PEW sounds. Channel 3 is a programmable wave channel which I have exactly 0 clue how to use but I think is involved with playing samples.
Channel 4 is the noise channel which has some kind of random number generator thing to make it sound garbled and fuzzy, which is great for making crash sounds.
Register 0: Sweep and on/off
Channel 1
7 Unused
6-4 Sweep time(update rate) (if 0, sweeping is off)
3 Sweep Direction (1: decrease, 0: increase)
2-0 Sweep RtShift amount (if 0, sweeping is off)
Channel 3
7 Channel 3 Master on/off
6-0 Unused
Channels 2 and 4
7-0 Unused
Register 1: Wave pattern duty and sound length
Channels 1 2 and 4
7-6 Wave pattern duty (only on channels 1 and 2)
5-0 Length counter load register
Channel 3
7-0 Length counter load register
Register 2: Volume Envelope (Makes the volume get louder or quieter each "tick")
Channels 1 2 and 4
7-4 (Initial) Channel Volume
3 Volume sweep direction (0: down; 1: up)
2-0 Length of each step in sweep (if 0, sweeping is off)
NOTE: each step is n/64 seconds long, where n is 1-7
Channel 3
7 Unused
6-5 Volume Level (0: Mute; 1: 100%; 2: 50% [rtshift 1]; 3: 25% [rtshift 2])
4-0 Unused
Register 3: Frequency LSbs and noise options
Channels 1 2 and 3
7-0 8 Least Significant bits of frequency (3 MSbs are in set 5)
Channel 4
7-4 Shift clock frequency (s)
3 Shift Register width (0: 15 bits; 1: 7 bits)
2-0 Dividing Ratio of frequency (r)
Frequency = 524288 Hz / r / 2^(s+1) ;For r=0 use r=0.5 instead
Register 4: Playback and frequency MSbs
Channels 1 2 3 and 4
7 Initialize (trigger channel start, AKA channel INIT) (Write only)
6 Consecutive select/length counter enable (Read/Write)
5-3 Unused
2-0 3 Most Significant bits of frequency (channels 1,2,3) (Read?/Write)
Most of that came straight from Jonathan Gevaryahu's GBSOUND.txt
Here is an example pew sound from my game (which you can check out at my website SpaceKitty Games) "PEWPEW":
NR52_REG = 0x80;
NR51_REG = 0x11;
NR50_REG = 0x77;
NR10_REG = 0x1E;
NR11_REG = 0x10;
NR12_REG = 0xF3;
NR13_REG = 0x00;
NR14_REG = 0x87;
you can put that into the main function just like that and as long as you include gb.h it will play.