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 }