If you have been playing along with this tutorial-of-sorts you will now be in a position to display backgrounds, create and manipulate sprites, deal with input and create your own graphics. You're now more than halfway to having all the tools you need to write your own games.
But it's a bit quiet isn't it? After all, what is a game without some kind of noise.
There are, at a very broad level, three ways of generating noise from the NGPC for the hobbyist programmer:
- Direct manipulation of the sound driver
- 8 Bit Sampled Sound Effects
- Background Music
I'll get the first one out of the way before we get much further into this. I am not the person to explain the intricacies of direct sound manipulation, but a bit of trial and error will get you some quite satisfying bells, zaps and whistles.
The direct sound manipulation is built into the framework using the following functions:
- InstallSoundDriver() - just include a call to this in your code just after InitNGPC()
- InstallSounds() - provide an array of sound structures to the driver
- PlaySound() - plays one of the previously provided sounds
The complication here is in InstallSounds(), you'll need to create an array of sound effects using the SOUNDEFFECT structure from library.h as follows:
- Channel
- Length
- Repeat
- InitialTone
- ToneStep
- ToneSpeed
- ToneOWB
- ToneLowerLimit
- ToneUpperLimit
- InitialVol
- VolStep
- VolSpeed
- VolOWB
- VolLowerLimit
- VolUpperLimit
If you understand what all this means, then you're already ahead of me. But basically, by changing the parameters (specifically the tone ones) you can manipulate the sound engine to produce a variety of squawks, beeps and buzzes. In my experience, keep it short and you can't go far wrong.
As a starter for ten, this code allows you to use two different sound effects by pushing the A or B buttons.
enum { SND_SIREN = 1, SND_CHIRP = 2, NUM_SOUNDS = SND_CHIRP }; const SOUNDEFFECT Sounds[NUM_SOUNDS] = { { 2, 0x60, 0, 0x60, 0x08, 0x01, 0x02, 0x40, 0x80, 0x0f, 0,0,0,0,0 }, // SND_SIREN { 1, 0x40, 0, 0x80, 0x20, 0x01, 0x01, 0x44, 0x82, 0x0f, 0,0,0,0,0 } //SND_CHIRP }; void main() { InitNGPC(); InstallSoundDriver(); InstallSounds(Sounds, NUM_SOUNDS); while(1) { if (JOYPAD & J_A) // if A is pressed play the siren sound PlaySound(SND_SIREN); if (JOYPAD & J_B) // if B is pressed play the chirp sound PlaySound(SND_CHIRP); while(JOYPAD); // wait for button release }
You can experiment with those values as you see fit to get quite a decent library of sound effects. I use a small custom ROM to play with the sounds and simply keep a note of ones I like.
Sampled sound effects are the next easiest way to get your NGPC to make a sound, and much easier to get "complex" sound effects. You'll need a couple of external tools to get the best out of them, but this is pretty easy. The basic steps are:
- Create/Copy/Steal an 8x8x8 (bits/KHz/Channels) .WAV file
- Run it through wav2c.exe (available here)
- #include it in your code
- Call SysPlayWave()
I'm not sure whether SysPlayWave() ever made it into the framework, nor whether it has simply been replaced by some of the undoubtably more complete sound code, but for now we can get our machine to play a sample by adding SYSTEM.LIB to your makefile and including the following snippet in library.c (and create the relevant definition in library.h)
// SysPlayWave // u8 wave[]; void SysPlayWave(u8 *wave) { __asm(" extern large WAVE_OUT"); __asm(" ld xwa,(XSP+0x4)"); __asm(" ld xhl3,xwa"); //__asm(" ldl xhl3,_wave"); __asm(" ldb ra3,1"); __asm(" calr WAVE_OUT"); }
What does all that do? Ah, well, you know that Arthur C Clarke quote about science and magic? This definitely falls on the side of Magic for me... Suffice to say, if you have sacrificed the chickens in the right order, the NGPC will make a reasonable stab at outputting your .wav file.
Be warned though. This is best suited for extremely short sounds - much less than a second - as it locks the NGPC out of all other processing while the sound plays and is strictly one sample at a time. Just keep that in mind before thinking that you can create a cacophonous noise by overlaying samples. It's very handy for game over noises and the like though.
The third, and most complex, way to get sound is to use Ivan Macintosh's NeoTracker plugin. This is brilliant for background music but does require a base level of musical know-how (or in my case, you can find a friend!)
I won't go into the intricacies of using the Tracker itself but similarly to NeoTile, exporting a track essentially creates a C header file. You'll need to include this in your main.c and then you can call it as follows.
#include "Neotracker_Music.h" void main() { InitNGPC(); NeoTracker_InstallDriver(); NeoTracker_InstallDriver(); // Music_Data and Music_Len constants will be in the // exported NeoTracker.h file NeoTracker_SendGroup(Music_Data, Music_Len); // BGM_MUSIC will also be as exported by NeoTracker NeoTracker_PlayMusic(BGM_MUSIC); // Your normal code here NeoTracker_StopAll(); }
Now, my musical ability is, if anything, even further down the tree than my artistic skill, but luckily NeoTracker has the ability to import .mod files with very little fuss.
Also be aware that NeoTracker and the library sound functions are mutually exclusive as they both sit in the same part of the NGPC - you can have both running in the same code, but you will have to initialise each independently as you use them. It took me longer than I'd like to admit to work that out.
And with that... this series of tutorials comes to a halt. There's a lot more that I haven't gone into in any detail, but with the last half dozen posts you should have enough information available to have a crack at doing something yourself. I haven't tried to turn you into a programmer as there are already more and better general C coding tutorials available that will help you fill in the gaps. Experiment, steal my code if it helps, and try to turn it into your own thing. Most of all, have fun doing it.
I would like to personally thank the giants of the NGPC development world, who's shoulders I merely stand on, so in no particular order thanks go out to Flavor, Thor, Ivan Macintosh, Judge, Steve Robb, Jim Bagley, Loic Julien, Dark Fader, Jeff Frohwein and every other bugger whose hard work I have shamelessly ripped off over the years.
If you want to try any of this on real hardware, your best bet is to get in touch with Flavor over at the flashmasta website. Ed is heavily focused on the awesome Raspberry Pi based GPA project, but is still producing both NGPC and Wonderswan flash cartridges.
Good luck and happy coding. Let me know how you get on...