diff options
author | Jens Arnold <amiconn@rockbox.org> | 2005-03-02 23:49:38 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2005-03-02 23:49:38 +0000 |
commit | 384de102469fee4e0792df8fe38586d3206774ed (patch) | |
tree | ee5342103e17738acfb8421328ea7c57433f55e6 /apps/plugins/rockboy/sound.c | |
parent | 48dad47df98bdec632e8930b6a97359dc2c428f5 (diff) | |
download | rockbox-384de102469fee4e0792df8fe38586d3206774ed.tar.gz rockbox-384de102469fee4e0792df8fe38586d3206774ed.zip |
Rockboy - gameboy emulation for rockbox, based on gnuboy. Still a bit early, but already playable on iRiver H1xx and the simulators. The archos recorder version is currently rather slow...
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6104 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/rockboy/sound.c')
-rw-r--r-- | apps/plugins/rockboy/sound.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/apps/plugins/rockboy/sound.c b/apps/plugins/rockboy/sound.c new file mode 100644 index 0000000000..edf31d81b7 --- /dev/null +++ b/apps/plugins/rockboy/sound.c | |||
@@ -0,0 +1,466 @@ | |||
1 | |||
2 | |||
3 | |||
4 | #include "rockmacros.h" | ||
5 | #include "defs.h" | ||
6 | #include "pcm.h" | ||
7 | #include "sound.h" | ||
8 | #include "cpu.h" | ||
9 | #include "hw.h" | ||
10 | #include "regs.h" | ||
11 | #include "rc.h" | ||
12 | #include "noise.h" | ||
13 | |||
14 | |||
15 | static const byte dmgwave[16] = | ||
16 | { | ||
17 | 0xac, 0xdd, 0xda, 0x48, | ||
18 | 0x36, 0x02, 0xcf, 0x16, | ||
19 | 0x2c, 0x04, 0xe5, 0x2c, | ||
20 | 0xac, 0xdd, 0xda, 0x48 | ||
21 | }; | ||
22 | |||
23 | static const byte cgbwave[16] = | ||
24 | { | ||
25 | 0x00, 0xff, 0x00, 0xff, | ||
26 | 0x00, 0xff, 0x00, 0xff, | ||
27 | 0x00, 0xff, 0x00, 0xff, | ||
28 | 0x00, 0xff, 0x00, 0xff, | ||
29 | }; | ||
30 | |||
31 | |||
32 | static const byte sqwave[4][8] = | ||
33 | { | ||
34 | { 0, 0,-1, 0, 0, 0, 0, 0 }, | ||
35 | { 0,-1,-1, 0, 0, 0, 0, 0 }, | ||
36 | { -1,-1,-1,-1, 0, 0, 0, 0 }, | ||
37 | { -1, 0, 0,-1,-1,-1,-1,-1 } | ||
38 | }; | ||
39 | |||
40 | static const int freqtab[8] = | ||
41 | { | ||
42 | (1<<14)*2, | ||
43 | (1<<14), | ||
44 | (1<<14)/2, | ||
45 | (1<<14)/3, | ||
46 | (1<<14)/4, | ||
47 | (1<<14)/5, | ||
48 | (1<<14)/6, | ||
49 | (1<<14)/7 | ||
50 | }; | ||
51 | |||
52 | struct snd snd; | ||
53 | int pcm_submit(void); | ||
54 | |||
55 | #define RATE (snd.rate) | ||
56 | #define WAVE (snd.wave) /* ram.hi+0x30 */ | ||
57 | #define S1 (snd.ch[0]) | ||
58 | #define S2 (snd.ch[1]) | ||
59 | #define S3 (snd.ch[2]) | ||
60 | #define S4 (snd.ch[3]) | ||
61 | |||
62 | rcvar_t sound_exports[] = | ||
63 | { | ||
64 | RCV_END | ||
65 | }; | ||
66 | |||
67 | |||
68 | static void s1_freq_d(int d) | ||
69 | { | ||
70 | if (RATE > (d<<4)) S1.freq = 0; | ||
71 | else S1.freq = (RATE << 17)/d; | ||
72 | } | ||
73 | |||
74 | static void s1_freq(void) | ||
75 | { | ||
76 | s1_freq_d(2048 - (((R_NR14&7)<<8) + R_NR13)); | ||
77 | } | ||
78 | |||
79 | static void s2_freq(void) | ||
80 | { | ||
81 | int d = 2048 - (((R_NR24&7)<<8) + R_NR23); | ||
82 | if (RATE > (d<<4)) S2.freq = 0; | ||
83 | else S2.freq = (RATE << 17)/d; | ||
84 | } | ||
85 | |||
86 | static void s3_freq(void) | ||
87 | { | ||
88 | int d = 2048 - (((R_NR34&7)<<8) + R_NR33); | ||
89 | if (RATE > (d<<3)) S3.freq = 0; | ||
90 | else S3.freq = (RATE << 21)/d; | ||
91 | } | ||
92 | |||
93 | static void s4_freq(void) | ||
94 | { | ||
95 | S4.freq = (freqtab[R_NR43&7] >> (R_NR43 >> 4)) * RATE; | ||
96 | if (S4.freq >> 18) S4.freq = 1<<18; | ||
97 | } | ||
98 | |||
99 | void sound_dirty(void) | ||
100 | { | ||
101 | S1.swlen = ((R_NR10>>4) & 7) << 14; | ||
102 | S1.len = (64-(R_NR11&63)) << 13; | ||
103 | S1.envol = R_NR12 >> 4; | ||
104 | S1.endir = (R_NR12>>3) & 1; | ||
105 | S1.endir |= S1.endir - 1; | ||
106 | S1.enlen = (R_NR12 & 7) << 15; | ||
107 | s1_freq(); | ||
108 | S2.len = (64-(R_NR21&63)) << 13; | ||
109 | S2.envol = R_NR22 >> 4; | ||
110 | S2.endir = (R_NR22>>3) & 1; | ||
111 | S2.endir |= S2.endir - 1; | ||
112 | S2.enlen = (R_NR22 & 7) << 15; | ||
113 | s2_freq(); | ||
114 | S3.len = (256-R_NR31) << 20; | ||
115 | s3_freq(); | ||
116 | S4.len = (64-(R_NR41&63)) << 13; | ||
117 | S4.envol = R_NR42 >> 4; | ||
118 | S4.endir = (R_NR42>>3) & 1; | ||
119 | S4.endir |= S4.endir - 1; | ||
120 | S4.enlen = (R_NR42 & 7) << 15; | ||
121 | s4_freq(); | ||
122 | } | ||
123 | |||
124 | void sound_off(void) | ||
125 | { | ||
126 | memset(&S1, 0, sizeof S1); | ||
127 | memset(&S2, 0, sizeof S2); | ||
128 | memset(&S3, 0, sizeof S3); | ||
129 | memset(&S4, 0, sizeof S4); | ||
130 | R_NR10 = 0x80; | ||
131 | R_NR11 = 0xBF; | ||
132 | R_NR12 = 0xF3; | ||
133 | R_NR14 = 0xBF; | ||
134 | R_NR21 = 0x3F; | ||
135 | R_NR22 = 0x00; | ||
136 | R_NR24 = 0xBF; | ||
137 | R_NR30 = 0x7F; | ||
138 | R_NR31 = 0xFF; | ||
139 | R_NR32 = 0x9F; | ||
140 | R_NR33 = 0xBF; | ||
141 | R_NR41 = 0xFF; | ||
142 | R_NR42 = 0x00; | ||
143 | R_NR43 = 0x00; | ||
144 | R_NR44 = 0xBF; | ||
145 | R_NR50 = 0x77; | ||
146 | R_NR51 = 0xF3; | ||
147 | R_NR52 = 0xF1; | ||
148 | sound_dirty(); | ||
149 | } | ||
150 | |||
151 | void sound_reset(void) | ||
152 | { | ||
153 | memset(&snd, 0, sizeof snd); | ||
154 | if (pcm.hz) snd.rate = (1<<21) / pcm.hz; | ||
155 | else snd.rate = 0; | ||
156 | memcpy(WAVE, hw.cgb ? cgbwave : dmgwave, 16); | ||
157 | memcpy(ram.hi+0x30, WAVE, 16); | ||
158 | sound_off(); | ||
159 | } | ||
160 | |||
161 | |||
162 | void sound_mix(void) | ||
163 | { | ||
164 | int s, l, r, f, n; | ||
165 | |||
166 | if (!RATE || cpu.snd < RATE) return; | ||
167 | |||
168 | for (; cpu.snd >= RATE; cpu.snd -= RATE) | ||
169 | { | ||
170 | l = r = 0; | ||
171 | |||
172 | if (S1.on) | ||
173 | { | ||
174 | s = sqwave[R_NR11>>6][(S1.pos>>18)&7] & S1.envol; | ||
175 | S1.pos += S1.freq; | ||
176 | if ((R_NR14 & 64) && ((S1.cnt += RATE) >= S1.len)) | ||
177 | S1.on = 0; | ||
178 | if (S1.enlen && (S1.encnt += RATE) >= S1.enlen) | ||
179 | { | ||
180 | S1.encnt -= S1.enlen; | ||
181 | S1.envol += S1.endir; | ||
182 | if (S1.envol < 0) S1.envol = 0; | ||
183 | if (S1.envol > 15) S1.envol = 15; | ||
184 | } | ||
185 | if (S1.swlen && (S1.swcnt += RATE) >= S1.swlen) | ||
186 | { | ||
187 | S1.swcnt -= S1.swlen; | ||
188 | f = S1.swfreq; | ||
189 | n = (R_NR10 & 7); | ||
190 | if (R_NR10 & 8) f -= (f >> n); | ||
191 | else f += (f >> n); | ||
192 | if (f > 2047) | ||
193 | S1.on = 0; | ||
194 | else | ||
195 | { | ||
196 | S1.swfreq = f; | ||
197 | R_NR13 = f; | ||
198 | R_NR14 = (R_NR14 & 0xF8) | (f>>8); | ||
199 | s1_freq_d(2048 - f); | ||
200 | } | ||
201 | } | ||
202 | s <<= 2; | ||
203 | if (R_NR51 & 1) r += s; | ||
204 | if (R_NR51 & 16) l += s; | ||
205 | } | ||
206 | |||
207 | if (S2.on) | ||
208 | { | ||
209 | s = sqwave[R_NR21>>6][(S2.pos>>18)&7] & S2.envol; | ||
210 | S2.pos += S2.freq; | ||
211 | if ((R_NR24 & 64) && ((S2.cnt += RATE) >= S2.len)) | ||
212 | S2.on = 0; | ||
213 | if (S2.enlen && (S2.encnt += RATE) >= S2.enlen) | ||
214 | { | ||
215 | S2.encnt -= S2.enlen; | ||
216 | S2.envol += S2.endir; | ||
217 | if (S2.envol < 0) S2.envol = 0; | ||
218 | if (S2.envol > 15) S2.envol = 15; | ||
219 | } | ||
220 | s <<= 2; | ||
221 | if (R_NR51 & 2) r += s; | ||
222 | if (R_NR51 & 32) l += s; | ||
223 | } | ||
224 | |||
225 | if (S3.on) | ||
226 | { | ||
227 | s = WAVE[(S3.pos>>22) & 15]; | ||
228 | if (S3.pos & (1<<21)) s &= 15; | ||
229 | else s >>= 4; | ||
230 | s -= 8; | ||
231 | S3.pos += S3.freq; | ||
232 | if ((R_NR34 & 64) && ((S3.cnt += RATE) >= S3.len)) | ||
233 | S3.on = 0; | ||
234 | if (R_NR32 & 96) s <<= (3 - ((R_NR32>>5)&3)); | ||
235 | else s = 0; | ||
236 | if (R_NR51 & 4) r += s; | ||
237 | if (R_NR51 & 64) l += s; | ||
238 | } | ||
239 | |||
240 | if (S4.on) | ||
241 | { | ||
242 | if (R_NR43 & 8) s = 1 & (noise7[ | ||
243 | (S4.pos>>20)&15] >> (7-((S4.pos>>17)&7))); | ||
244 | else s = 1 & (noise15[ | ||
245 | (S4.pos>>20)&4095] >> (7-((S4.pos>>17)&7))); | ||
246 | s = (-s) & S4.envol; | ||
247 | S4.pos += S4.freq; | ||
248 | if ((R_NR44 & 64) && ((S4.cnt += RATE) >= S4.len)) | ||
249 | S4.on = 0; | ||
250 | if (S4.enlen && (S4.encnt += RATE) >= S4.enlen) | ||
251 | { | ||
252 | S4.encnt -= S4.enlen; | ||
253 | S4.envol += S4.endir; | ||
254 | if (S4.envol < 0) S4.envol = 0; | ||
255 | if (S4.envol > 15) S4.envol = 15; | ||
256 | } | ||
257 | s += s << 1; | ||
258 | if (R_NR51 & 8) r += s; | ||
259 | if (R_NR51 & 128) l += s; | ||
260 | } | ||
261 | |||
262 | l *= (R_NR50 & 0x07); | ||
263 | r *= ((R_NR50 & 0x70)>>4); | ||
264 | l >>= 4; | ||
265 | r >>= 4; | ||
266 | |||
267 | if (l > 127) l = 127; | ||
268 | else if (l < -128) l = -128; | ||
269 | if (r > 127) r = 127; | ||
270 | else if (r < -128) r = -128; | ||
271 | |||
272 | if (pcm.buf) | ||
273 | { | ||
274 | if (pcm.pos >= pcm.len) | ||
275 | pcm_submit(); | ||
276 | if (pcm.stereo) | ||
277 | { | ||
278 | pcm.buf[pcm.pos++] = l+128; | ||
279 | pcm.buf[pcm.pos++] = r+128; | ||
280 | } | ||
281 | else pcm.buf[pcm.pos++] = ((l+r)>>1)+128; | ||
282 | } | ||
283 | } | ||
284 | R_NR52 = (R_NR52&0xf0) | S1.on | (S2.on<<1) | (S3.on<<2) | (S4.on<<3); | ||
285 | } | ||
286 | |||
287 | |||
288 | |||
289 | byte sound_read(byte r) | ||
290 | { | ||
291 | sound_mix(); | ||
292 | /* printf("read %02X: %02X\n", r, REG(r)); */ | ||
293 | return REG(r); | ||
294 | } | ||
295 | |||
296 | void s1_init(void) | ||
297 | { | ||
298 | S1.swcnt = 0; | ||
299 | S1.swfreq = ((R_NR14&7)<<8) + R_NR13; | ||
300 | S1.envol = R_NR12 >> 4; | ||
301 | S1.endir = (R_NR12>>3) & 1; | ||
302 | S1.endir |= S1.endir - 1; | ||
303 | S1.enlen = (R_NR12 & 7) << 15; | ||
304 | if (!S1.on) S1.pos = 0; | ||
305 | S1.on = 1; | ||
306 | S1.cnt = 0; | ||
307 | S1.encnt = 0; | ||
308 | } | ||
309 | |||
310 | void s2_init(void) | ||
311 | { | ||
312 | S2.envol = R_NR22 >> 4; | ||
313 | S2.endir = (R_NR22>>3) & 1; | ||
314 | S2.endir |= S2.endir - 1; | ||
315 | S2.enlen = (R_NR22 & 7) << 15; | ||
316 | if (!S2.on) S2.pos = 0; | ||
317 | S2.on = 1; | ||
318 | S2.cnt = 0; | ||
319 | S2.encnt = 0; | ||
320 | } | ||
321 | |||
322 | void s3_init(void) | ||
323 | { | ||
324 | int i; | ||
325 | if (!S3.on) S3.pos = 0; | ||
326 | S3.cnt = 0; | ||
327 | S3.on = R_NR30 >> 7; | ||
328 | if (S3.on) for (i = 0; i < 16; i++) | ||
329 | ram.hi[i+0x30] = 0x13 ^ ram.hi[i+0x31]; | ||
330 | } | ||
331 | |||
332 | void s4_init(void) | ||
333 | { | ||
334 | S4.envol = R_NR42 >> 4; | ||
335 | S4.endir = (R_NR42>>3) & 1; | ||
336 | S4.endir |= S4.endir - 1; | ||
337 | S4.enlen = (R_NR42 & 7) << 15; | ||
338 | S4.on = 1; | ||
339 | S4.pos = 0; | ||
340 | S4.cnt = 0; | ||
341 | S4.encnt = 0; | ||
342 | } | ||
343 | |||
344 | |||
345 | void sound_write(byte r, byte b) | ||
346 | { | ||
347 | #if 0 | ||
348 | static void *timer; | ||
349 | if (!timer) timer = sys_timer(); | ||
350 | printf("write %02X: %02X @ %d\n", r, b, sys_elapsed(timer)); | ||
351 | #endif | ||
352 | |||
353 | if (!(R_NR52 & 128) && r != RI_NR52) return; | ||
354 | if ((r & 0xF0) == 0x30) | ||
355 | { | ||
356 | if (S3.on) sound_mix(); | ||
357 | if (!S3.on) | ||
358 | WAVE[r-0x30] = ram.hi[r] = b; | ||
359 | return; | ||
360 | } | ||
361 | sound_mix(); | ||
362 | switch (r) | ||
363 | { | ||
364 | case RI_NR10: | ||
365 | R_NR10 = b; | ||
366 | S1.swlen = ((R_NR10>>4) & 7) << 14; | ||
367 | S1.swfreq = ((R_NR14&7)<<8) + R_NR13; | ||
368 | break; | ||
369 | case RI_NR11: | ||
370 | R_NR11 = b; | ||
371 | S1.len = (64-(R_NR11&63)) << 13; | ||
372 | break; | ||
373 | case RI_NR12: | ||
374 | R_NR12 = b; | ||
375 | S1.envol = R_NR12 >> 4; | ||
376 | S1.endir = (R_NR12>>3) & 1; | ||
377 | S1.endir |= S1.endir - 1; | ||
378 | S1.enlen = (R_NR12 & 7) << 15; | ||
379 | break; | ||
380 | case RI_NR13: | ||
381 | R_NR13 = b; | ||
382 | s1_freq(); | ||
383 | break; | ||
384 | case RI_NR14: | ||
385 | R_NR14 = b; | ||
386 | s1_freq(); | ||
387 | if (b & 128) s1_init(); | ||
388 | break; | ||
389 | case RI_NR21: | ||
390 | R_NR21 = b; | ||
391 | S2.len = (64-(R_NR21&63)) << 13; | ||
392 | break; | ||
393 | case RI_NR22: | ||
394 | R_NR22 = b; | ||
395 | S2.envol = R_NR22 >> 4; | ||
396 | S2.endir = (R_NR22>>3) & 1; | ||
397 | S2.endir |= S2.endir - 1; | ||
398 | S2.enlen = (R_NR22 & 7) << 15; | ||
399 | break; | ||
400 | case RI_NR23: | ||
401 | R_NR23 = b; | ||
402 | s2_freq(); | ||
403 | break; | ||
404 | case RI_NR24: | ||
405 | R_NR24 = b; | ||
406 | s2_freq(); | ||
407 | if (b & 128) s2_init(); | ||
408 | break; | ||
409 | case RI_NR30: | ||
410 | R_NR30 = b; | ||
411 | if (!(b & 128)) S3.on = 0; | ||
412 | break; | ||
413 | case RI_NR31: | ||
414 | R_NR31 = b; | ||
415 | S3.len = (256-R_NR31) << 13; | ||
416 | break; | ||
417 | case RI_NR32: | ||
418 | R_NR32 = b; | ||
419 | break; | ||
420 | case RI_NR33: | ||
421 | R_NR33 = b; | ||
422 | s3_freq(); | ||
423 | break; | ||
424 | case RI_NR34: | ||
425 | R_NR34 = b; | ||
426 | s3_freq(); | ||
427 | if (b & 128) s3_init(); | ||
428 | break; | ||
429 | case RI_NR41: | ||
430 | R_NR41 = b; | ||
431 | S4.len = (64-(R_NR41&63)) << 13; | ||
432 | break; | ||
433 | case RI_NR42: | ||
434 | R_NR42 = b; | ||
435 | S4.envol = R_NR42 >> 4; | ||
436 | S4.endir = (R_NR42>>3) & 1; | ||
437 | S4.endir |= S4.endir - 1; | ||
438 | S4.enlen = (R_NR42 & 7) << 15; | ||
439 | break; | ||
440 | case RI_NR43: | ||
441 | R_NR43 = b; | ||
442 | s4_freq(); | ||
443 | break; | ||
444 | case RI_NR44: | ||
445 | R_NR44 = b; | ||
446 | if (b & 128) s4_init(); | ||
447 | break; | ||
448 | case RI_NR50: | ||
449 | R_NR50 = b; | ||
450 | break; | ||
451 | case RI_NR51: | ||
452 | R_NR51 = b; | ||
453 | break; | ||
454 | case RI_NR52: | ||
455 | R_NR52 = b; | ||
456 | if (!(R_NR52 & 128)) | ||
457 | sound_off(); | ||
458 | break; | ||
459 | default: | ||
460 | return; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | |||
465 | |||
466 | |||