Mercurial > hg > index.fcgi > lj > lj046
comparison src/dssound7.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:634a226b549c |
---|---|
1 /*--------------------------------------------------------------------------------- | |
2 | |
3 LOCKJAW Tetromino Game: ARM7 sound code | |
4 | |
5 based on | |
6 default ARM7 core | |
7 | |
8 Copyright (C) 2007 | |
9 Damian Yerrick (tepples) | |
10 | |
11 This software is provided 'as-is', without any express or implied | |
12 warranty. In no event will the authors be held liable for any | |
13 damages arising from the use of this software. | |
14 | |
15 Permission is granted to anyone to use this software for any | |
16 purpose, including commercial applications, and to alter it and | |
17 redistribute it freely, subject to the following restrictions: | |
18 | |
19 1. The origin of this software must not be misrepresented; you | |
20 must not claim that you wrote the original software. If you use | |
21 this software in a product, an acknowledgment in the product | |
22 documentation would be appreciated but is not required. | |
23 2. Altered source versions must be plainly marked as such, and | |
24 must not be misrepresented as being the original software. | |
25 3. This notice may not be removed or altered from any source | |
26 distribution. | |
27 | |
28 ---------------------------------------------------------------------------------*/ | |
29 #include <nds.h> | |
30 #include <sys/types.h> | |
31 | |
32 extern const unsigned short midi2psgFreq[120]; | |
33 | |
34 #define C(octave) (octave * 12 + 0) | |
35 #define CS(octave) (octave * 12 + 1) | |
36 #define D(octave) (octave * 12 + 2) | |
37 #define DS(octave) (octave * 12 + 3) | |
38 #define E(octave) (octave * 12 + 4) | |
39 #define F(octave) (octave * 12 + 5) | |
40 #define FS(octave) (octave * 12 + 6) | |
41 #define G(octave) (octave * 12 + 7) | |
42 #define GS(octave) (octave * 12 + 8) | |
43 #define A(octave) (octave * 12 + 9) | |
44 #define AS(octave) (octave * 12 + 10) | |
45 #define B(octave) (octave * 12 + 11) | |
46 | |
47 | |
48 #define N_MUSIC_CHANNELS 2 | |
49 | |
50 static unsigned short chNote[N_MUSIC_CHANNELS]; | |
51 static unsigned char chVol[N_MUSIC_CHANNELS]; | |
52 | |
53 | |
54 static const unsigned char startVol[N_MUSIC_CHANNELS] = {32, 30}; | |
55 static const unsigned char fade[N_MUSIC_CHANNELS] = {0, 1}; | |
56 static const unsigned char chDuty[N_MUSIC_CHANNELS] = {0, 3}; | |
57 | |
58 static const signed char bassLine[64] = { | |
59 A(2), 0, A(3), 0, -1, 0, A(2), 0, | |
60 A(3), 0, -1, 0, 0, 0, 0, 0, | |
61 0, 0, 0, 0, 0, 0, 0, 0, | |
62 C(3), 0, C(4), 0, G(2), 0, G(3), 0, | |
63 A(2), 0, A(3), 0, -1, 0, A(2), 0, | |
64 A(3), 0, -1, 0, 0, 0, 0, 0, | |
65 0, 0, 0, 0, 0, 0, 0, 0, | |
66 C(3), 0, C(4), 0, G(2), 0, G(3), 0, | |
67 }; | |
68 | |
69 static const signed char mel1[64] = { | |
70 E(6), 0, 0, 0, B(5), 0, C(6), 0, | |
71 D(6), 0, 0, 0, C(6), 0, B(5), 0, | |
72 A(5), 0, 0, 0, A(5), 0, C(6), 0, | |
73 E(6), 0, 0, 0, D(6), 0, C(6), 0, | |
74 B(5), 0, 0, 0, 0, 0, C(6), 0, | |
75 D(6), 0, 0, 0, E(6), 0, 0, 0, | |
76 C(6), 0, 0, 0, A(5), 0, 0, 0, | |
77 A(5) | |
78 }; | |
79 | |
80 static const signed char mel2[64] = { | |
81 0, 0, D(6), 0, 0, 0, F(6), 0, | |
82 A(6), 0, 0, 0, G(6), 0, F(6), 0, | |
83 E(6), 0, 0, 0, 0, 0, C(6), 0, | |
84 E(6), 0, 0, 0, D(6), 0, C(6), 0, | |
85 B(5), 0, 0, 0, B(5), 0, C(6), 0, | |
86 D(6), 0, 0, 0, E(6), 0, 0, 0, | |
87 C(6), 0, 0, 0, A(5), 0, 0, 0, | |
88 A(5) | |
89 }; | |
90 | |
91 static const signed char *const scripts[4][N_MUSIC_CHANNELS] = { | |
92 { bassLine, mel1 }, | |
93 { bassLine, mel1 }, | |
94 { bassLine, mel2 }, | |
95 { bassLine, mel2 } | |
96 }; | |
97 | |
98 int order = 0; | |
99 char ticksLeft = 1; | |
100 char row = 0; | |
101 char musicPaused = 1; | |
102 | |
103 /* | |
104 * Plays a repeating drum track and bass track. | |
105 */ | |
106 void ljMusic(void) { | |
107 if (musicPaused) { | |
108 for (int ch = 0; ch < N_MUSIC_CHANNELS; ++ch) { | |
109 chVol[ch] = 0; | |
110 } | |
111 } else if (--ticksLeft <= 0) { | |
112 ticksLeft += 6; | |
113 for (int ch = 0; ch < N_MUSIC_CHANNELS; ++ch) { | |
114 const signed char *script = scripts[order][ch]; | |
115 int note = script ? script[(int)row] : 0; | |
116 if (note < 0) { | |
117 chVol[ch] = 0; | |
118 } else if (note > 0) { | |
119 chVol[ch] = startVol[ch]; | |
120 chNote[ch] = midi2psgFreq[note]; | |
121 } | |
122 } | |
123 ++row; | |
124 if (row >= 64) { | |
125 row = 0; | |
126 ++order; | |
127 if (order == 4) { | |
128 order = 0; | |
129 } | |
130 } | |
131 } | |
132 | |
133 | |
134 // Play notes | |
135 for (int ch = 0; ch < N_MUSIC_CHANNELS; ++ch) { | |
136 SCHANNEL_CR(8 + ch) = SCHANNEL_ENABLE | SOUND_FORMAT_PSG | SOUND_PAN(64) | |
137 | (chDuty[ch] << 24) | chVol[ch]; | |
138 SCHANNEL_TIMER(8 + ch) = chNote[ch]; | |
139 | |
140 // update volumes | |
141 if (chVol[ch] > fade[ch]) { | |
142 chVol[ch] -= fade[ch]; | |
143 } else { | |
144 chVol[ch] = 0; | |
145 } | |
146 } | |
147 } | |
148 | |
149 #define FX(note, volume, duty) ((note) | ((volume) << 7) | ((duty) << 14)) | |
150 | |
151 static const u16 rotateEffect[] = { | |
152 0, 6, | |
153 FX(A(5), 32, 1), FX(A(5), 8, 1), | |
154 FX(D(6), 32, 1), FX(D(6), 8, 1), | |
155 FX(G(6), 32, 1), FX(G(6), 8, 1) | |
156 }; | |
157 | |
158 static const u16 moveEffect[] = { | |
159 0, 2, | |
160 FX(A(6), 32, 1), FX(A(6), 8, 1) | |
161 }; | |
162 | |
163 static const u16 landEffect[] = { | |
164 0, 8, | |
165 FX(C(4), 64, 3), FX(GS(3), 56, 3), | |
166 FX(F(3), 48, 3), FX(D(3), 40, 3), | |
167 FX(C(3), 32, 3), FX(B(2), 24, 3), | |
168 FX(C(3), 16, 3), FX(B(2), 8, 3), | |
169 }; | |
170 | |
171 static const u16 lockEffect[] = { | |
172 1, 2, | |
173 FX(C(8), 16, 1), FX(C(8), 4, 1) | |
174 }; | |
175 | |
176 static const u16 lineEffect[] = { | |
177 0, 15, | |
178 FX(C(6), 64, 2), FX(DS(6), 59, 2), FX(F(6), 54, 2), | |
179 FX(C(6), 49, 2), FX(D(6), 44, 2), FX(F(6), 39, 2), | |
180 FX(C(6), 34, 3), FX(DS(6), 29, 3), FX(F(6), 24, 3), | |
181 FX(C(6), 20, 3), FX(D(6), 16, 3), FX(F(6), 12, 3), | |
182 FX(C(6), 9, 3), FX(DS(6), 6, 3), FX(F(6), 3, 3) | |
183 }; | |
184 | |
185 static const u16 homerEffect[] = { | |
186 0, 25, | |
187 FX(C(6), 64, 2), FX(DS(6), 59, 2), FX(F(6), 54, 2), | |
188 FX(C(6), 49, 2), FX(D(6), 44, 2), FX(F(6), 39, 2), | |
189 FX(C(6), 34, 3), FX(DS(6), 29, 3), FX(F(6), 24, 3), | |
190 FX(C(6), 20, 3), | |
191 FX(DS(6), 64, 2), FX(FS(6), 59, 2), FX(GS(6), 54, 2), | |
192 FX(DS(6), 49, 2), FX(F(6), 44, 2), FX(GS(6), 39, 2), | |
193 FX(DS(6), 34, 3), FX(FS(6), 29, 3), FX(GS(6), 24, 3), | |
194 FX(DS(6), 20, 3), FX(F(6), 16, 3), FX(GS(6), 12, 3), | |
195 FX(DS(6), 9, 3), FX(F(6), 6, 3), FX(GS(6), 3, 3) | |
196 }; | |
197 | |
198 static const u16 streakEffect[] = { | |
199 0, 35, | |
200 FX(C(6), 64, 2), FX(DS(6), 59, 2), FX(F(6), 54, 2), | |
201 FX(C(6), 49, 2), FX(D(6), 44, 2), FX(F(6), 39, 2), | |
202 FX(C(6), 34, 3), FX(DS(6), 29, 3), FX(F(6), 24, 3), | |
203 FX(C(6), 20, 3), | |
204 FX(DS(6), 64, 2), FX(FS(6), 59, 2), FX(GS(6), 54, 2), | |
205 FX(DS(6), 49, 2), FX(F(6), 44, 2), FX(GS(6), 39, 2), | |
206 FX(DS(6), 34, 3), FX(FS(6), 29, 3), FX(GS(6), 24, 3), | |
207 FX(DS(6), 20, 3), | |
208 FX(FS(6), 64, 2), FX(A(6), 59, 2), FX(B(6), 54, 2), | |
209 FX(FS(6), 49, 2), FX(GS(6), 44, 2), FX(B(6), 39, 2), | |
210 FX(FS(6), 34, 3), FX(A(6), 29, 3), FX(B(6), 24, 3), | |
211 FX(FS(6), 20, 3), FX(GS(6), 16, 3), FX(B(6), 12, 3), | |
212 FX(FS(6), 9, 3), FX(GS(6), 6, 3), FX(B(6), 3, 3) | |
213 }; | |
214 | |
215 static const u16 holdEffect[] = { | |
216 1, 10, | |
217 FX(E(5), 20, 0), FX(G(5), 25, 0), | |
218 FX(B(5), 30, 0), FX(B(5), 30, 0), | |
219 FX(G(5), 28, 0), FX(E(5), 24, 0), | |
220 FX(D(5), 20, 0), FX(C(5), 15, 0), | |
221 FX(C(5), 10, 0), FX(C(5), 5, 0) | |
222 }; | |
223 | |
224 | |
225 static const u16 irsEffect[] = { | |
226 0, 12, | |
227 FX(CS(7), 40, 3), FX(CS(7), 40, 3), | |
228 FX(FS(7), 40, 3), FX(FS(7), 40, 3), | |
229 FX(B(7), 40, 3), FX(B(7), 35, 3), | |
230 FX(B(7), 30, 3), FX(B(7), 25, 3), | |
231 FX(B(7), 20, 3), FX(B(7), 15, 3), | |
232 FX(B(7), 10, 3), FX(B(7), 5, 3), | |
233 }; | |
234 | |
235 static const u16 countEffect[] = { | |
236 0, 14, | |
237 FX(D(5), 64, 0), FX(D(5), 64, 0), | |
238 FX(CS(5), 64, 0), FX(CS(5), 64, 0), | |
239 FX(C(5), 64, 1), FX(C(5), 64, 1), | |
240 FX(B(4), 64, 1), FX(AS(4), 64, 1), | |
241 FX(A(4), 64, 2), FX(GS(4), 64, 2), | |
242 FX(GS(4), 64, 3), FX(G(4), 48, 3), | |
243 FX(G(4), 32, 3), FX(G(4), 16, 3), | |
244 }; | |
245 | |
246 static const u16 winEffect1[] = { | |
247 0, 54, | |
248 FX(C(6), 32, 2), FX(C(6), 48, 1), FX(C(6), 48, 1), FX(C(6), 48, 1), | |
249 FX(C(6), 32, 2), 0, 0, 0, 0, | |
250 FX(AS(5), 32, 2), FX(AS(5), 48, 1), FX(AS(5), 48, 1), FX(AS(5), 48, 1), | |
251 FX(AS(5), 32, 2), 0, 0, 0, 0, | |
252 FX(C(6), 32, 2), FX(C(6), 48, 1), FX(C(6), 48, 1), FX(C(6), 48, 1), | |
253 FX(D(6), 32, 2), 0, 0, 0, 0, | |
254 | |
255 FX(D(6), 32, 2), FX(D(6), 48, 1), FX(D(6), 48, 1), FX(D(6), 48, 1), | |
256 FX(D(6), 47, 1), FX(D(6), 46, 1), FX(D(6), 45, 1), FX(D(6), 44, 1), | |
257 FX(D(6), 43, 1), FX(D(6), 42, 1), FX(D(6), 41, 1), FX(D(6), 40, 1), | |
258 FX(D(6), 39, 1), FX(D(6), 38, 1), FX(D(6), 37, 1), FX(D(6), 36, 1), | |
259 FX(D(6), 35, 1), FX(D(6), 34, 1), FX(D(6), 33, 1), FX(D(6), 32, 1), | |
260 FX(D(6), 31, 1), FX(D(6), 30, 1), FX(D(6), 29, 1), FX(D(6), 28, 1), | |
261 FX(D(6), 27, 1), FX(D(6), 26, 1), FX(D(6), 25, 1), FX(D(6), 24, 1), | |
262 FX(D(6), 18, 2), FX(D(6), 12, 2), FX(D(6), 6, 2) | |
263 }; | |
264 | |
265 static const u16 winEffect2[] = { | |
266 0, 54, | |
267 FX(E(6), 32, 2), FX(E(6), 48, 1), FX(E(6), 48, 1), FX(E(6), 48, 1), | |
268 FX(E(6), 32, 2), 0, 0, 0, 0, | |
269 FX(D(6), 32, 2), FX(D(6), 48, 1), FX(D(6), 48, 1), FX(D(6), 48, 1), | |
270 FX(D(6), 32, 2), 0, 0, 0, 0, | |
271 FX(E(6), 32, 2), FX(E(6), 48, 1), FX(E(6), 48, 1), FX(E(6), 48, 1), | |
272 FX(E(6), 32, 2), 0, 0, 0, 0, | |
273 | |
274 FX(FS(6), 32, 2), FX(FS(6), 48, 1), FX(FS(6), 48, 1), FX(FS(6), 48, 1), | |
275 FX(FS(6), 47, 1), FX(FS(6), 46, 1), FX(FS(6), 45, 1), FX(FS(6), 44, 1), | |
276 FX(FS(6), 43, 1), FX(FS(6), 42, 1), FX(FS(6), 41, 1), FX(FS(6), 40, 1), | |
277 FX(FS(6), 39, 1), FX(FS(6), 38, 1), FX(FS(6), 37, 1), FX(FS(6), 36, 1), | |
278 FX(FS(6), 35, 1), FX(FS(6), 34, 1), FX(FS(6), 33, 1), FX(FS(6), 32, 1), | |
279 FX(FS(6), 31, 1), FX(FS(6), 30, 1), FX(FS(6), 29, 1), FX(FS(6), 28, 1), | |
280 FX(FS(6), 27, 1), FX(FS(6), 26, 1), FX(FS(6), 25, 1), FX(FS(6), 24, 1), | |
281 FX(FS(6), 18, 2), FX(FS(6), 12, 2), FX(FS(6), 6, 2) | |
282 }; | |
283 | |
284 static const u16 dieEffect1[] = { | |
285 0, 60, | |
286 FX(E(3), 60, 2), FX(E(3), 59, 2), FX(E(3), 58, 2), FX(E(3), 57, 2), | |
287 FX(E(3), 56, 2), FX(E(3), 55, 2), FX(E(3), 54, 2), FX(E(3), 53, 2), | |
288 FX(E(3), 52, 2), FX(E(3), 51, 2), FX(E(3), 50, 2), FX(E(3), 49, 2), | |
289 FX(E(3), 48, 2), FX(E(3), 47, 2), FX(E(3), 46, 2), FX(E(3), 45, 2), | |
290 FX(E(3), 44, 2), FX(E(3), 43, 2), FX(E(3), 42, 2), FX(E(3), 41, 2), | |
291 FX(E(3), 40, 2), FX(E(3), 39, 2), FX(E(3), 38, 2), FX(E(3), 37, 2), | |
292 FX(E(3), 36, 2), FX(E(3), 35, 2), FX(E(3), 34, 2), FX(E(3), 33, 2), | |
293 FX(E(3), 32, 2), FX(E(3), 31, 2), FX(E(3), 30, 2), FX(E(3), 29, 2), | |
294 FX(E(3), 28, 2), FX(E(3), 27, 2), FX(E(3), 26, 2), FX(E(3), 25, 2), | |
295 FX(E(3), 24, 2), FX(E(3), 23, 2), FX(E(3), 22, 2), FX(E(3), 21, 2), | |
296 FX(E(3), 20, 2), FX(E(3), 19, 2), FX(E(3), 18, 2), FX(E(3), 17, 2), | |
297 FX(E(3), 16, 2), FX(E(3), 15, 2), FX(E(3), 14, 2), FX(E(3), 13, 2), | |
298 FX(E(3), 12, 2), FX(E(3), 11, 2), FX(E(3), 10, 2), FX(E(3), 9, 2), | |
299 FX(E(3), 8, 2), FX(E(3), 7, 2), FX(E(3), 6, 2), FX(E(3), 5, 2), | |
300 FX(E(3), 4, 2), FX(E(3), 3, 2), FX(E(3), 2, 2), FX(E(3), 1, 2) | |
301 }; | |
302 | |
303 static const u16 dieEffect2[] = { | |
304 1, 60, | |
305 FX(E(4), 60, 2), FX(B(3), 59, 2), FX(E(3), 58, 2), FX(E(3), 57, 2), | |
306 FX(E(3), 56, 2), FX(E(3), 55, 2), FX(E(3), 54, 2), FX(E(3), 53, 2), | |
307 FX(E(3), 52, 2), FX(E(3), 51, 2), FX(E(3), 50, 2), FX(E(3), 49, 2), | |
308 FX(E(3), 48, 2), FX(E(3), 47, 2), FX(E(3), 46, 2), FX(E(3), 45, 2), | |
309 FX(E(3), 44, 2), FX(E(3), 43, 2), FX(E(3), 42, 2), FX(E(3), 41, 2), | |
310 FX(E(3), 40, 2), FX(E(3), 39, 2), FX(E(3), 38, 2), FX(E(3), 37, 2), | |
311 FX(E(3), 36, 2), FX(E(3), 35, 2), FX(E(3), 34, 2), FX(E(3), 33, 2), | |
312 FX(E(3), 32, 2), FX(E(3), 31, 2), FX(E(3), 30, 2), FX(E(3), 29, 2), | |
313 FX(E(3), 28, 2), FX(E(3), 27, 2), FX(E(3), 26, 2), FX(E(3), 25, 2), | |
314 FX(E(3), 24, 2), FX(E(3), 23, 2), FX(E(3), 22, 2), FX(E(3), 21, 2), | |
315 FX(E(3), 20, 2), FX(E(3), 19, 2), FX(E(3), 18, 2), FX(E(3), 17, 2), | |
316 FX(E(3), 16, 2), FX(E(3), 15, 2), FX(E(3), 14, 2), FX(E(3), 13, 2), | |
317 FX(E(3), 12, 2), FX(E(3), 11, 2), FX(E(3), 10, 2), FX(E(3), 9, 2), | |
318 FX(E(3), 8, 2), FX(E(3), 7, 2), FX(E(3), 6, 2), FX(E(3), 5, 2), | |
319 FX(E(3), 4, 2), FX(E(3), 3, 2), FX(E(3), 2, 2), FX(E(3), 1, 2) | |
320 }; | |
321 | |
322 static const u16 *effects[32] = { | |
323 rotateEffect, | |
324 moveEffect, | |
325 NULL, // drop: not used | |
326 landEffect, | |
327 lockEffect, | |
328 lineEffect, | |
329 homerEffect, | |
330 streakEffect, | |
331 NULL, // spawn | |
332 holdEffect, // hold | |
333 irsEffect, // irs | |
334 NULL, // 4x4 square | |
335 NULL, NULL, NULL, NULL, // unused | |
336 dieEffect1, dieEffect2 | |
337 }; | |
338 | |
339 | |
340 | |
341 static const u16 *fxPtr[5]; | |
342 static u8 fxLen[5]; | |
343 static s8 lastCD; | |
344 | |
345 | |
346 | |
347 static void startEffect(const u16 *s) { | |
348 | |
349 // skip effects that lack an actual effect | |
350 if (!s) { | |
351 return; | |
352 } | |
353 | |
354 unsigned int type = s[0]; | |
355 unsigned int len = s[1]; | |
356 unsigned int min = 0; | |
357 unsigned int max = 2; | |
358 | |
359 if (type > 0) { | |
360 min = 3; | |
361 max = 4; | |
362 } | |
363 | |
364 // prepare to kill the channel with the shortest time remaining | |
365 unsigned int shortestLen = fxLen[min]; | |
366 unsigned int shortestCh = min; | |
367 for (int ch = min + 1; ch <= max; ++ch) { | |
368 if (fxLen[ch] < shortestLen) { | |
369 shortestLen = fxLen[ch]; | |
370 shortestCh = ch; | |
371 } | |
372 } | |
373 | |
374 // if the channel is suitable, kill it | |
375 if (shortestLen < len) { | |
376 fxPtr[shortestCh] = s + 2; | |
377 fxLen[shortestCh] = len; | |
378 } | |
379 } | |
380 | |
381 static void pollEffects(void) { | |
382 for (int ch = 0; ch < 5; ++ch) { | |
383 unsigned int note = 36; | |
384 unsigned int vol = 0; | |
385 unsigned int duty = 0; | |
386 if (fxLen[ch] > 0) { | |
387 unsigned int data = *fxPtr[ch]++; | |
388 duty = (data >> 14) & 0x03; | |
389 vol = (data >> 7) & 0x7F; | |
390 note = data & 0x7F; | |
391 --fxLen[ch]; | |
392 } | |
393 SCHANNEL_CR(11 + ch) = SCHANNEL_ENABLE | SOUND_FORMAT_PSG | SOUND_PAN(64) | |
394 | (duty << 24) | vol; | |
395 SCHANNEL_TIMER(11 + ch) = midi2psgFreq[note]; | |
396 } | |
397 } | |
398 | |
399 void ljSoundEffects(unsigned long int sounds, | |
400 int countdown) { | |
401 | |
402 // cancel out overlapping line clear sounds | |
403 if (sounds & 0x0080) { | |
404 sounds &= ~0x0060; | |
405 } else if (sounds & 0x0040) { | |
406 sounds &= ~0x0020; | |
407 } | |
408 | |
409 for (int y = 0; sounds; ++y, sounds >>= 1) { | |
410 if (sounds & 1) { | |
411 startEffect(effects[y]); | |
412 } | |
413 } | |
414 if (countdown < 0) { | |
415 countdown = 0; | |
416 } else if (countdown > 6) { | |
417 countdown = 6; | |
418 } | |
419 if (countdown < lastCD) { | |
420 if (countdown > 0) { | |
421 startEffect(countEffect); | |
422 } else { | |
423 startEffect(winEffect1); | |
424 startEffect(winEffect2); | |
425 } | |
426 } | |
427 lastCD = countdown; | |
428 pollEffects(); | |
429 } |