comparison src/gbasound.c @ 0:c84446dfb3f5

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