Mercurial > hg > index.fcgi > lj > lj046
view src/dssound7.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line source
1 /*---------------------------------------------------------------------------------
3 LOCKJAW Tetromino Game: ARM7 sound code
5 based on
6 default ARM7 core
8 Copyright (C) 2007
9 Damian Yerrick (tepples)
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.
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:
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.
28 ---------------------------------------------------------------------------------*/
29 #include <nds.h>
30 #include <sys/types.h>
32 extern const unsigned short midi2psgFreq[120];
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)
48 #define N_MUSIC_CHANNELS 2
50 static unsigned short chNote[N_MUSIC_CHANNELS];
51 static unsigned char chVol[N_MUSIC_CHANNELS];
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};
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 };
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 };
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 };
91 static const signed char *const scripts[4][N_MUSIC_CHANNELS] = {
92 { bassLine, mel1 },
93 { bassLine, mel1 },
94 { bassLine, mel2 },
95 { bassLine, mel2 }
96 };
98 int order = 0;
99 char ticksLeft = 1;
100 char row = 0;
101 char musicPaused = 1;
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 }
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];
140 // update volumes
141 if (chVol[ch] > fade[ch]) {
142 chVol[ch] -= fade[ch];
143 } else {
144 chVol[ch] = 0;
145 }
146 }
147 }
149 #define FX(note, volume, duty) ((note) | ((volume) << 7) | ((duty) << 14))
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 };
158 static const u16 moveEffect[] = {
159 0, 2,
160 FX(A(6), 32, 1), FX(A(6), 8, 1)
161 };
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 };
171 static const u16 lockEffect[] = {
172 1, 2,
173 FX(C(8), 16, 1), FX(C(8), 4, 1)
174 };
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 };
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 };
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 };
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 };
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 };
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 };
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,
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 };
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,
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 };
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 };
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 };
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 };
341 static const u16 *fxPtr[5];
342 static u8 fxLen[5];
343 static s8 lastCD;
347 static void startEffect(const u16 *s) {
349 // skip effects that lack an actual effect
350 if (!s) {
351 return;
352 }
354 unsigned int type = s[0];
355 unsigned int len = s[1];
356 unsigned int min = 0;
357 unsigned int max = 2;
359 if (type > 0) {
360 min = 3;
361 max = 4;
362 }
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 }
374 // if the channel is suitable, kill it
375 if (shortestLen < len) {
376 fxPtr[shortestCh] = s + 2;
377 fxLen[shortestCh] = len;
378 }
379 }
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 }
399 void ljSoundEffects(unsigned long int sounds,
400 int countdown) {
402 // cancel out overlapping line clear sounds
403 if (sounds & 0x0080) {
404 sounds &= ~0x0060;
405 } else if (sounds & 0x0040) {
406 sounds &= ~0x0020;
407 }
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 }