|
| 1 | +# Audio |
| 2 | + |
| 3 | +In the last few chapters we implemented the bulk of our game's interactivity, but it would be nice to add some feedback to make brick-breaking a bit more satisfying. |
| 4 | + |
| 5 | +The Game Boy has 4 channels for producing sound: 2 pulse channels, a wave channel, and a noise channel. |
| 6 | +Each type of channel has a unique type of sound that it can produce. |
| 7 | +For example, the pulse channels can play notes, making them ideal for melodies, while the noise channel is less melodic, making it better for percussion. |
| 8 | +The wave channel is unique in that it can be used to play simple waveforms. |
| 9 | +You can almost think of this as a custom instrument, though it's very limited. |
| 10 | + |
| 11 | +Here's a diagram from [this page](https://gbdev.io/pandocs/Audio.html) of the Pandocs showing each channel. |
| 12 | +<svg viewBox="0 0 480 220" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg"> |
| 13 | + <defs> |
| 14 | + <style type="text/css"> |
| 15 | + text { |
| 16 | + fill: var(--fg); |
| 17 | + dominant-baseline: middle; |
| 18 | + } |
| 19 | + .centered { text-anchor: middle; } |
| 20 | + .right { text-anchor: end; } |
| 21 | + rect, path, use { |
| 22 | + stroke: var(--fg); |
| 23 | + fill: var(--fg); |
| 24 | + } |
| 25 | + .inverted { |
| 26 | + stroke: var(--bg); |
| 27 | + fill: var(--bg); |
| 28 | + } |
| 29 | + .unfilled { |
| 30 | + fill: none !important; |
| 31 | + } |
| 32 | + .no-stroke { |
| 33 | + stroke: none !important; |
| 34 | + } |
| 35 | + </style> |
| 36 | + <path d="M 0,-5 |
| 37 | + v 10 |
| 38 | + l 10,-5 |
| 39 | + z" id="arrow-head"></path> |
| 40 | + </defs> |
| 41 | + <text x="85" y="36" class="right">Channel 1</text> |
| 42 | + <rect x="95" y="15" width="40" height="40"></rect> |
| 43 | + <path d="M 95,45 |
| 44 | + h 10 |
| 45 | + v -20 |
| 46 | + h 10 |
| 47 | + v 20 |
| 48 | + h 10 |
| 49 | + v -20 |
| 50 | + h 10" class="inverted unfilled"></path> |
| 51 | + <text x="85" y="86" class="right">Channel 2</text> |
| 52 | + <rect x="95" y="65" width="40" height="40"></rect> |
| 53 | + <path d="M 95,95 |
| 54 | + h 10 |
| 55 | + v -20 |
| 56 | + h 10 |
| 57 | + v 20 |
| 58 | + h 10 |
| 59 | + v -20 |
| 60 | + h 10" class="inverted unfilled"></path> |
| 61 | + <text x="85" y="136" class="right">Channel 3</text> |
| 62 | + <rect x="95" y="115" width="40" height="40"></rect> |
| 63 | + <path d="M 95,141 |
| 64 | + h 2 |
| 65 | + v -2 |
| 66 | + h 2 |
| 67 | + v -3 |
| 68 | + h 2 |
| 69 | + v -3 |
| 70 | + h 2 |
| 71 | + v -3 |
| 72 | + h 2 |
| 73 | + v -2 |
| 74 | + h 2 |
| 75 | + v -1 |
| 76 | + h 2 |
| 77 | + v 1 |
| 78 | + h 2 |
| 79 | + v 2 |
| 80 | + h 2 |
| 81 | + v 5 |
| 82 | + h 2 |
| 83 | + v 4 |
| 84 | + h 2 |
| 85 | + v 2 |
| 86 | + h 2 |
| 87 | + v 1 |
| 88 | + h 4 |
| 89 | + v -10 |
| 90 | + h 2 |
| 91 | + v -5 |
| 92 | + h 2 |
| 93 | + v 15 |
| 94 | + h 2 |
| 95 | + v -14 |
| 96 | + h 2 |
| 97 | + v 7 |
| 98 | + h 2 |
| 99 | + v 4 |
| 100 | + h 2 |
| 101 | + v 2 |
| 102 | + h 4 |
| 103 | + v 1 |
| 104 | + h 4 |
| 105 | + v -1 |
| 106 | + h 2 |
| 107 | + v -1 |
| 108 | + h 2 |
| 109 | + v -2 |
| 110 | + h 2 |
| 111 | + v -2 |
| 112 | + h 2 |
| 113 | + v -3 |
| 114 | + h 2 |
| 115 | + v -2 |
| 116 | + h 2 |
| 117 | + v -2 |
| 118 | + h 2" class="inverted unfilled"></path> |
| 119 | + <text x="85" y="186" class="right">Channel 4</text> |
| 120 | + <rect x="95" y="165" width="40" height="40"></rect> |
| 121 | + <path d="M 95,195 |
| 122 | + h 2 |
| 123 | + v -20 |
| 124 | + h 2 |
| 125 | + v 20 |
| 126 | + h 5 |
| 127 | + v -20 |
| 128 | + h 2 |
| 129 | + v 20 |
| 130 | + h 1 |
| 131 | + v -20 |
| 132 | + h 6 |
| 133 | + v 20 |
| 134 | + h 3 |
| 135 | + v -20 |
| 136 | + h 2 |
| 137 | + v 20 |
| 138 | + h 1 |
| 139 | + v -20 |
| 140 | + h 2 |
| 141 | + v 20 |
| 142 | + h 5 |
| 143 | + v -20 |
| 144 | + h 1 |
| 145 | + v 20 |
| 146 | + h 4 |
| 147 | + v -20 |
| 148 | + h 2 |
| 149 | + v 20 |
| 150 | + h 1 |
| 151 | + v -20 |
| 152 | + h 1" class="inverted unfilled"></path> |
| 153 | + <path d="M 135,35 |
| 154 | + h 30 |
| 155 | + m -30,50 |
| 156 | + h 30 |
| 157 | + m -30,50 |
| 158 | + h 30 |
| 159 | + m -30,50 |
| 160 | + h 30 |
| 161 | + v -150 |
| 162 | + m 0,75 |
| 163 | + h 30" class="unfilled"></path> |
| 164 | + <use x="185" y="110" href="#arrow-head"></use> |
| 165 | + <rect x="195" y="95" width="60" height="30"></rect> |
| 166 | + <text x="225" y="110" class="centered inverted no-stroke">Mixer</text> |
| 167 | + <path d="M 255,102 |
| 168 | + h 30" class="unfilled"></path> |
| 169 | + <use x="275" y="102" href="#arrow-head"></use> |
| 170 | + <path d="M 255,118 |
| 171 | + h 30" class="unfilled"></path> |
| 172 | + <use x="275" y="118" href="#arrow-head"></use> |
| 173 | + <rect x="285" y="95" width="80" height="30"></rect> |
| 174 | + <text x="325" y="110" class="centered inverted no-stroke">Amplifier</text> |
| 175 | + <path d="M 365,102 |
| 176 | + h 30" class="unfilled"></path> |
| 177 | + <use x="385" y="102" href="#arrow-head"></use> |
| 178 | + <path d="M 365,118 |
| 179 | + h 30" class="unfilled"></path> |
| 180 | + <use x="385" y="118" href="#arrow-head"></use> |
| 181 | + <rect x="395" y="95" width="80" height="30"></rect> |
| 182 | + <text x="435" y="110" class="centered inverted no-stroke">Output</text> |
| 183 | +</svg> |
| 184 | + |
| 185 | +Audio channels can be controlled through the Game Boy's large number of "NR" registers. |
| 186 | +Each of these registers configures the behavior of a channel and can be used to play specific sounds. |
| 187 | +In addition, channels 1, 2, and 4 have a hardware envelope, which is used to fade the channel out over time; this is very useful for simple sound effects! |
| 188 | + |
| 189 | +::: tip |
| 190 | + |
| 191 | +If you'd like a more in-depth look at the audio registers, check out the [audio articles](https://gbdev.io/pandocs/Audio.html) on the Pandocs. |
| 192 | + |
| 193 | +::: |
| 194 | + |
| 195 | +For the simple sound effects in our game, all we need to do is write a few values to the NR registers, and the Game Boy will handle the rest. |
| 196 | +We can use a tool like [gbsfx studio](https://daid.github.io/gbsfx-studio/) to create a sound we like, and then copy the code into our game to play it. |
| 197 | + |
| 198 | +We'll start with a "bounce" sound effect. Let's use channel 2, which is a pulse channel, and play a short note. |
| 199 | +The following code is a sample bounce sound, but feel free to play around and find a sound you like. |
| 200 | + |
| 201 | +```rgbasm |
| 202 | +ld a, $85 |
| 203 | +ld [rNR21], a |
| 204 | +ld a, $70 |
| 205 | +ld [rNR22], a |
| 206 | +ld a, $0d |
| 207 | +ld [rNR23], a |
| 208 | +ld a, $c3 |
| 209 | +ld [rNR24], a |
| 210 | +``` |
| 211 | + |
| 212 | +To use this in our game, we'll put it within a short function which we can call any time a bounce sound needs to be played. |
| 213 | + |
| 214 | +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/audio/main.asm:bounce-sound}} |
| 215 | +{{#include ../../unbricked/audio/main.asm:bounce-sound}} |
| 216 | +``` |
| 217 | + |
| 218 | +Now just call this function at the end of each of our bouncing checks. |
| 219 | +Don't forget the paddle! |
| 220 | + |
| 221 | +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/audio/main.asm:updated-bounce}} |
| 222 | +{{#include ../../unbricked/audio/main.asm:updated-bounce}} |
| 223 | +``` |
| 224 | + |
| 225 | +A sound effect would make destroying bricks a lot more satisfying. |
| 226 | +This time, let's use the noise channel to play a sound. |
| 227 | +Since we're using a different channel, the "bounce" and "break" sounds can overlap without any issue! |
| 228 | + |
| 229 | +This is an example sound, but feel free to create your own. |
| 230 | + |
| 231 | +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/audio/main.asm:break-sound}} |
| 232 | +{{#include ../../unbricked/audio/main.asm:break-sound}} |
| 233 | +``` |
| 234 | + |
| 235 | +And just like with the bouncing sound, we'll need to call this function in our brick-breaking code. |
| 236 | + |
| 237 | +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/audio/main.asm:check-for-brick}} |
| 238 | +{{#include ../../unbricked/audio/main.asm:check-for-brick}} |
| 239 | +``` |
| 240 | + |
| 241 | +Now the game has some audiotory feedback! |
0 commit comments