annotate src/gbasound.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 #include <string.h>
paulo@0 2 #include "ljgba.h"
paulo@0 3 #include "pin8gba_sound.h"
paulo@0 4 extern const unsigned short note_freqs[];
paulo@0 5
paulo@0 6 static const u16 moveEffect[] = {
paulo@0 7 0, 3,
paulo@0 8 0x516D, 0x0000, 0x0100
paulo@0 9 };
paulo@0 10
paulo@0 11 static const u16 rotateEffect[] = {
paulo@0 12 1, 7,
paulo@0 13 0x5161, 0x0000, 0x5166, 0x0000, 0x516b, 0x0000, 0x0100
paulo@0 14 };
paulo@0 15
paulo@0 16 static const u16 landEffect[] = {
paulo@0 17 1, 6,
paulo@0 18 0x8188, 0x7185, 0x6182, 0x5181, 0x3180, 0x0000
paulo@0 19 };
paulo@0 20
paulo@0 21 static const u16 lockEffect[] = {
paulo@0 22 3, 1,
paulo@0 23 0x2138
paulo@0 24 };
paulo@0 25
paulo@0 26 static const u16 lineEffect[] = {
paulo@0 27 0, 12,
paulo@0 28 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9,
paulo@0 29 0x61A4, 0x51A6, 0x41A9, 0x31A4, 0x21A7, 0x11A9
paulo@0 30 };
paulo@0 31
paulo@0 32 static const u16 holdEffect[] = {
paulo@0 33 3, 8,
paulo@0 34 0x3030, 0x0000, 0x4032, 0x0000, 0x3130, 0x0000, 0x202c, 0x2128
paulo@0 35 };
paulo@0 36
paulo@0 37 static const u16 irsRotateEffect[] = {
paulo@0 38 1, 12,
paulo@0 39 0x5161, 0x51B1, 0x5166, 0x51B6, 0x516B, 0x51BB, 0x0000, 0x0000,
paulo@0 40 0x0000, 0x0000, 0x0000, 0x0100
paulo@0 41 };
paulo@0 42
paulo@0 43 static const u16 homerEffect[] = {
paulo@0 44 0, 22,
paulo@0 45 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9,
paulo@0 46 0x61A4, 0x51A6, 0x41A9, 0x31A4,
paulo@0 47 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC,
paulo@0 48 0x51A7, 0x41A9, 0x31AC, 0x21A7, 0x11AA, 0x01AC
paulo@0 49 };
paulo@0 50
paulo@0 51 static const u16 streakEffect[] = {
paulo@0 52 0, 30,
paulo@0 53 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9,
paulo@0 54 0x61A4, 0x51A6, 0x41A9, 0x31A4,
paulo@0 55 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC,
paulo@0 56 0x51A7, 0x41A9, 0x31AC, 0x21A7,
paulo@0 57 0xB1AA, 0xA1AC, 0x91AF, 0x71AA, 0x61AD, 0x51AF,
paulo@0 58 0x31AA, 0x21AC, 0x11AF, 0x01AA
paulo@0 59 };
paulo@0 60
paulo@0 61 static const u16 sectionEffect[] = {
paulo@0 62 1, 30,
paulo@0 63 0xB1B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 64 0xB1B4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 65 0xB1B7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 66 0xB1BC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 67 0xB1B0, 0x0000
paulo@0 68 };
paulo@0 69
paulo@0 70 static const u16 gameOverEffect1[] = {
paulo@0 71 1, 40,
paulo@0 72 0xF504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 73 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 74 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 75 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 76 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
paulo@0 77 };
paulo@0 78
paulo@0 79 static const u16 gameOverEffect2[] = {
paulo@0 80 3, 40,
paulo@0 81 0xC12C, 0xA725, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 82 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 84 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 85 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
paulo@0 86 };
paulo@0 87
paulo@0 88 static const u16 winEffect1[] = {
paulo@0 89 1, 30,
paulo@0 90 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 91 0xA562, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 92 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 93 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 94 0x0000, 0x0000
paulo@0 95 };
paulo@0 96
paulo@0 97 static const u16 winEffect2[] = {
paulo@0 98 0, 30,
paulo@0 99 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 100 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 101 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000,
paulo@0 102 0xA56A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
paulo@0 103 0x0000, 0x0000
paulo@0 104 };
paulo@0 105
paulo@0 106
paulo@0 107 static const u16 *const effects[] = {
paulo@0 108 moveEffect, rotateEffect, landEffect, lockEffect, lineEffect,
paulo@0 109 holdEffect, irsRotateEffect, homerEffect, streakEffect, sectionEffect,
paulo@0 110 gameOverEffect1, gameOverEffect2, winEffect1, winEffect2
paulo@0 111 };
paulo@0 112
paulo@0 113 const unsigned short tri_vol_table[5] = {
paulo@0 114 0,
paulo@0 115 TRILENVOL_25,
paulo@0 116 TRILENVOL_50,
paulo@0 117 TRILENVOL_75,
paulo@0 118 TRILENVOL_100
paulo@0 119 };
paulo@0 120
paulo@0 121 void play_note(unsigned int ch, unsigned int note, unsigned int instrument) {
paulo@0 122 switch (ch) {
paulo@0 123 case 0:
paulo@0 124 SQR1CTRL = instrument;
paulo@0 125 SQR1FREQ = note_freqs[note] | FREQ_RESET;
paulo@0 126 break;
paulo@0 127 case 1:
paulo@0 128 SQR2CTRL = instrument;
paulo@0 129 SQR2FREQ = note_freqs[note] | FREQ_RESET;
paulo@0 130 break;
paulo@0 131 case 2:
paulo@0 132 {
paulo@0 133 int vol = instrument >> 13;
paulo@0 134 TRILENVOL = tri_vol_table[(vol + 1) / 2];
paulo@0 135 TRIFREQ = note_freqs[note] | FREQ_RESET;
paulo@0 136 }
paulo@0 137 break;
paulo@0 138 case 3:
paulo@0 139 NOISECTRL = instrument;
paulo@0 140 {
paulo@0 141 int octave = (note & 0x3E) << 2;
paulo@0 142 int pitch = note & 0x03;
paulo@0 143 NOISEFREQ = (octave | pitch) ^ (0xF7 | FREQ_RESET);
paulo@0 144 }
paulo@0 145 break;
paulo@0 146 }
paulo@0 147 }
paulo@0 148
paulo@0 149 void gba_poll_sound(struct LJPCView *v) {
paulo@0 150 for (int i = 0; i < 4; ++i) {
paulo@0 151 if (v->sndLeft[i]) {
paulo@0 152 unsigned int data = *v->sndData[i];
paulo@0 153 if (data) {
paulo@0 154 play_note(i, data & 0x003F, data & 0xFFC0);
paulo@0 155 }
paulo@0 156 ++v->sndData[i];
paulo@0 157 --v->sndLeft[i];
paulo@0 158 }
paulo@0 159 }
paulo@0 160 }
paulo@0 161
paulo@0 162 void gba_play_sound(struct LJPCView *v, int effect) {
paulo@0 163 const u16 *data = effects[effect];
paulo@0 164 int ch = data[0];
paulo@0 165 int len = data[1];
paulo@0 166
paulo@0 167 // square waves can be played on either channel 0 or 1;
paulo@0 168 // switch if this channel is occupied and the other is free
paulo@0 169 if (ch < 2
paulo@0 170 && v->sndLeft[ch] > v->sndLeft[1 - ch]) {
paulo@0 171 ch = 1 - ch;
paulo@0 172 }
paulo@0 173 v->sndData[ch] = data + 2;
paulo@0 174 v->sndLeft[ch] = len;
paulo@0 175 }
paulo@0 176
paulo@0 177 /**
paulo@0 178 * Sets the sound bias to mid and resolution to 8-bit.
paulo@0 179 * Setting bias is needed because some launchers (such as pogoshell)
paulo@0 180 * set it to a state that mutes the tone generators.
paulo@0 181 */
paulo@0 182 static void set_bias(void)
paulo@0 183 {
paulo@0 184 asm volatile("mov r2, #2; lsl r2, #8; swi 0x19" ::: "r0", "r1", "r2", "r3");
paulo@0 185 SETSNDRES(1);
paulo@0 186 }
paulo@0 187
paulo@0 188 __attribute__((aligned(4)))
paulo@0 189 static const unsigned char triangleWave[16] = {
paulo@0 190 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
paulo@0 191 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
paulo@0 192 };
paulo@0 193 unsigned char lastWaveBank = 0;
paulo@0 194
paulo@0 195 void tri_set_waveform(const void *waveform) {
paulo@0 196 memcpy((void *)TRIWAVERAM, waveform, 16);
paulo@0 197 lastWaveBank = !lastWaveBank;
paulo@0 198 TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(lastWaveBank) | TRICTRL_ENABLE;
paulo@0 199 }
paulo@0 200
paulo@0 201 void install_sound(struct LJPCView *v) {
paulo@0 202 SNDSTAT = SNDSTAT_ENABLE;
paulo@0 203 DMGSNDCTRL = DMGSNDCTRL_LVOL(7) | DMGSNDCTRL_RVOL(7)
paulo@0 204 | DMGSNDCTRL_LSQR1 | DMGSNDCTRL_RSQR1
paulo@0 205 | DMGSNDCTRL_LSQR2 | DMGSNDCTRL_RSQR2
paulo@0 206 | DMGSNDCTRL_LTRI | DMGSNDCTRL_RTRI
paulo@0 207 | DMGSNDCTRL_LNOISE | DMGSNDCTRL_RNOISE;
paulo@0 208 DSOUNDCTRL = DSOUNDCTRL_DMG100;
paulo@0 209 set_bias();
paulo@0 210 SQR1SWEEP = SQR1SWEEP_OFF;
paulo@0 211
paulo@0 212 #if 0
paulo@0 213 TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(0) | TRICTRL_ENABLE;
paulo@0 214 tri_set_waveform(triangleWave);
paulo@0 215 TRILENVOL = 0;
paulo@0 216 TRIFREQ = 1024 | FREQ_RESET;
paulo@0 217 #endif
paulo@0 218
paulo@0 219 v->sndLeft[0] = 0;
paulo@0 220 v->sndLeft[1] = 0;
paulo@0 221 v->sndLeft[2] = 0;
paulo@0 222 v->sndLeft[3] = 0;
paulo@0 223 }
paulo@0 224