Squeezing more audio channels out of the 1989 Nintendo Gameboy, with utz and Quint
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
sines.mp3Audio output from a simple song using our 6-channel synthesis engine.MPEG Video - 792.35 kB - 04/01/2019 at 00:44 |
|
The Gameboy's two pulse channels produce a digital signal whose pulse width, frequency, amplitude, and decay can all be varied among discrete values within a range. Usually, a Gameboy game will read notes from a table and, at the beginning of each note, set these parameters accordingly. Decay happens automatically, so no unnecessary CPU time is wasted. Programmers can set a note once, then continue calculating necessary graphics and game logic until a new note needs to be played.
Using the pulse channels in this way is CPU efficient, but risks sounding same-y. There's only so much you can do with four parameters. Chiptunes (and good game soundtracks) use effects like pitch bends, vibrato, and arpeggios to spice up their use of the pulse channel. The Gameboy doesn't have hardware support for these effects, so they have to be implemented in software. As the notes play, the CPU will occasionally be interrupted to fiddle with parameters according to the effects desired. This puts the CPU in a more active role in audio, as it will need to modify the underlying hardware channel parameters in realtime.
Our mechanism for PU1 and PU2 channelhacking is similar to these sorts of effects in that it relies on the CPU to fiddle with note parameters while the note is still playing. The trick is to set up each pulse channel so it's outputting a high value for as long as possible, then reset the PWM position before it has the chance to transition from high to low. The amplitude can then be varied at a very high speed to create waves that are more complex than a pulse.
To do this, we first set the pulse channels to the lowest frequency and highest duty cycle available. This maximizes the time we have before the signal is pulled low again. During this time, code running in an interrupt is incrementing a value in memory (it's actually self-modifying) according to the frequency we want to produce. We can set up many such incrementers, but two is a good compromise number, giving us a total of four software wave channels: two for each of the two pulse channels. On each audio sample, each incrementer is used to index into a sine wave table. All the software channels for each hardware channel are then summed and the result is written to the amplitude of each channel.
Nothing is without consequence. By splitting the channel, we go from 15 possible amplitudes (excluding zero, which silences output) to a measly 7, since we have to be able to add the results without overflowing. This means the sine waves we produce when we combine channels are half the quality of a single software sine channel, i.e. the wave is discretized into fewer little stair-step voltage levels.
In summary, we've managed to split each of the two pulse waves in two. By keeping track of wave position in two "soft" channels, looking amplitude values up in a table, and summing the results, we can use simple waves to generate much more complex waves on a single channel.
You can hear this synthesis engine at work. PU1 is panned center, PU2 left, WAV right, and NOI center as well. You'll first hear one voice playing on PU1, then another voice will come in, also on PU1. PU2 will come in with the first drum hit, then the WAV channel after that. 6 total channels, playing simultaneously.
https://cdn.hackaday.io/files/1641617023464224/sines.mp3
I had also investigated a different mechanism of splitting the WAV channel onto two discrete channels. You may have seen the videos about...
Read more »Welcome! For the 2019 Retro Challenge, utz and I are adding additional sound capabilities to the original 1989 Nintendo Gameboy (DMG-01) by writing custom code that runs on normal Gameboy cartridges. To understand why and how, let's first look at how the Gameboy makes sound.
The Gameboy has five hardware sound channels. Each one can only produce one sound at a time. The code stored on a Gameboy cartridge can change certain parameters in each of these sound channels as the Gameboy runs it. With precise timing and clever composition, the Gameboy can produce some seriously impressive chiptunes.
Each sound channel is controlled by parameters, which differ depending on the channel. Let's dive deeper into the sounds each channel can make.
The first two channels are pulse wave generators, each of which can produce pulses with duty cycles of 12.5%, 25%, 50%, or 75%. These pulse channels sound quite synthetic. Music made with pulse waves either embraces the electronic sounds they produce, or applies heavy effects to make them sound like more traditional instruments. The Gameboy provides volume envelopes to change the volume of the generated sound over time to emulate real instrument effects, like the slow "decay" of vibrating strings in a guitar or piano.
The next channel can play arbitrary waveforms, though it has many limitations including very low sample quality (four bits) and hardware bugs that cause pops and hissing. Despite these issues, original games and homebrews alike use the wave channel for sample playback and to produce somewhat more natural-sounding waves than the pulse channels are capable of.
The noise channel makes noise, which is used for drum sounds and sound effects. At extreme parameter values, it can also be used to make weird and extremely limited tonal sounds.
There is a "fifth channel" allows game cartridges to provide analog input, which will then be mixed with the rest of the audio channels as if it were generated by the Gameboy itself. No game ever used this channel, but the GB303 homebrew hardware synthesizer (one of the most impressive Gameboy projects out there) uses this channel alone to produce sound. This doesn't really count as a Gameboy hardware channel, as it requires special external hardware that was never made commercially.
Ignoring the analog channel (as this is a software project), that gives utz and I four channels to work with.
Each of these channels should only be capable of making one sound at a time. No Gameboy game ever had more than three tonal sounds and one noise playing at a time. Clever composers evoke the feeling of multiple notes by quickly switching between pitches to make arpeggios that sound convincingly like chords, or switch between very different sound parameters to allow two different "instruments" to share the same channel. These techniques hide the Gameboy's simplistic nature by making it sound like it's much more powerful than it is, and the best chiptunes are made by composers who have mastered these techniques and adapted their compositions to make maximal use of them.
But what if we could do more? If we throw away the idea of making a proper game, with its intensive use of the CPU to put pretty pictures on the screen and move them around with precise timing, could we use the CPU cycles we save to squeeze more sound out of this 1989 portable gaming console?
As it turns out, yes. Thanks to extensive hardware documentation compiled by the Gameboy homebrew community, chiptune artists, and retro hardware hackers, as well as some impressive prior experimentation in this area, you can squeeze a hell of a lot out of this beige brick.
In the next post, I'll explain how this is accomplished. Stay tuned!
Quint
This post is part one in a series. Read the next post here.
For a deeper dive into the normal audio capabilities...
Read more »
Create an account to leave a comment. Already have an account? Log In.
Become a member to follow this project and never miss any updates