IntroductionLet me preface this article by saying that of all the hobbyist programming I have done, I enjoy developing for the Gameboy Advance the most. It strips away a lot the of the complexity normally associated with developing for the so-called "more powerful" machines. There's no hassling with drivers, complicated graphics APIs, or (cough) unruly operating systems. You get to program directly to the metal. And come on, how often does a hobbyist get to see his or her creation running on an actual commercial game console? On top of that, the dev hardware is reasonably cheap (a flash linker and cartridge will run you about $120), the standard C and C++ libraries are free (see Jason Wilkins Unofficial GameBoy Advance Software Development Kit), and the hardware documentation is abundant. Hmm… Well, maybe not that last one. While it's true that information about the video hardware of the GBA is plentiful on the 'net, the well appears to dry up as soon as one starts investigating the system's audio capabilities. (The notable exception to this is the Audio Advance website, but even it doesn't provide any examples of sample mixing) As you might have guessed, that's where this series of articles come in. By the time it is finished, I will have documented in careful detail the steps necessary to create a fully functional, eight channel, 22KHz sample mixer that uses (at most) 10% of the CPU. I should note that I will not be covering the Sound Channels 1-4, as they appear to be little more than a holdover from the Gameboy Color, and are not involved in the playback of recorded samples. Instead, I will cover what are called the "Direct Sound" hardware channels. LayoutThere will be three articles in this series by the time it is finished. A rough outline of their content is as follows:
Is everybody ready? Ok then, let's get started. Some BackgroundA fundamental concept that any GBA programmer should be familiar with is that all of the specialized functionality of the hardware is memory-mapped. This means that tasks like changing the video mode, reading input from the keypad, playing sounds, etc. can all be performed simply by writing to or reading from specific memory locations. For example, if I wanted to read the state of the keypad (ie. which of the buttons are currently being pressed), I would just read a 16-bit value from memory address 0x4000130 and interpret it accordingly. What makes this such a powerful concept is that it essentially boils down control of the specialized hardware to a few simple "switches." I would suggest checking out either Dovoto's The Pern Project or Brian Sowers GBA Development From the Ground Up for more information about the basic functionality of the GBA. Turning the thing onBefore we can make any noises with the GBA, we have to tell the hardware to turn the sound chip on. Luckily for you beginners, this is also a classically simple example of the memory-mapping I was just talking about. To enable the audio hardware, all we have to do is set bit 7 of REG_SOUNDCNT_X (a 32-bit value located at address 0x04000084) to 1. It amounts to a simple C statement: *(u32*)0x04000084 = 0x00000080; Kind of cryptic, huh? Let's add a couple of #defines to preserve our sanity, like this: #define REG_SOUNDCNT_X *(u32*)0x04000084 #define SND_ENABLED 0x00000080 Now our statement makes a lot more sense when we look at it. REG_SOUNDCNT_X = SND_ENABLED; |