diff options
Diffstat (limited to 'apps/codecs/spc.c')
-rw-r--r-- | apps/codecs/spc.c | 567 |
1 files changed, 12 insertions, 555 deletions
diff --git a/apps/codecs/spc.c b/apps/codecs/spc.c index 6c791b46a1..f2890cd4a4 100644 --- a/apps/codecs/spc.c +++ b/apps/codecs/spc.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | ||
8 | * | 9 | * |
9 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | 10 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) |
10 | * Copyright (C) 2004-2007 Shay Green (blargg) | 11 | * Copyright (C) 2004-2007 Shay Green (blargg) |
@@ -21,555 +22,11 @@ | |||
21 | /* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */ | 22 | /* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */ |
22 | /* DSP Based on Brad Martin's OpenSPC DSP emulator */ | 23 | /* DSP Based on Brad Martin's OpenSPC DSP emulator */ |
23 | /* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */ | 24 | /* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */ |
24 | |||
25 | #include "codeclib.h" | 25 | #include "codeclib.h" |
26 | #include "inttypes.h" | 26 | #include "spc/spc_codec.h" |
27 | #include "system.h" | ||
28 | |||
29 | /* rather than comment out asserts, just define NDEBUG */ | ||
30 | #define NDEBUG | ||
31 | #include <assert.h> | ||
32 | #undef check | ||
33 | #define check assert | ||
34 | |||
35 | CODEC_HEADER | ||
36 | |||
37 | #ifdef CPU_ARM | ||
38 | #undef ICODE_ATTR | ||
39 | #define ICODE_ATTR | ||
40 | |||
41 | #undef IDATA_ATTR | ||
42 | #define IDATA_ATTR | ||
43 | #endif | ||
44 | |||
45 | /* TGB is the only target fast enough for gaussian and realtime BRR decode */ | ||
46 | /* echo is almost fast enough but not quite */ | ||
47 | #ifndef TOSHIBA_GIGABEAT_F | ||
48 | /* Cache BRR waves */ | ||
49 | #define SPC_BRRCACHE 1 | ||
50 | |||
51 | /* Disable gaussian interpolation */ | ||
52 | #define SPC_NOINTERP 1 | ||
53 | |||
54 | #ifndef CPU_COLDFIRE | ||
55 | /* Disable echo processing */ | ||
56 | #define SPC_NOECHO 1 | ||
57 | #else | ||
58 | /* Enable echo processing */ | ||
59 | #define SPC_NOECHO 0 | ||
60 | #endif | ||
61 | #else | ||
62 | /* Don't cache BRR waves */ | ||
63 | #define SPC_BRRCACHE 0 | ||
64 | |||
65 | /* Allow gaussian interpolation */ | ||
66 | #define SPC_NOINTERP 0 | ||
67 | |||
68 | /* Allow echo processing */ | ||
69 | #define SPC_NOECHO 0 | ||
70 | #endif | ||
71 | |||
72 | /* Samples per channel per iteration */ | ||
73 | #ifdef CPU_COLDFIRE | ||
74 | #define WAV_CHUNK_SIZE 1024 | ||
75 | #else | ||
76 | #define WAV_CHUNK_SIZE 2048 | ||
77 | #endif | ||
78 | |||
79 | /* simple profiling with USEC_TIMER */ | ||
80 | /*#define SPC_PROFILE*/ | ||
81 | |||
82 | #include "spc/spc_profiler.h" | 27 | #include "spc/spc_profiler.h" |
83 | 28 | ||
84 | #define THIS struct Spc_Emu* const this | 29 | CODEC_HEADER |
85 | |||
86 | /**************** Little-endian handling ****************/ | ||
87 | |||
88 | static inline unsigned get_le16( void const* p ) | ||
89 | { | ||
90 | return ((unsigned char const*) p) [1] * 0x100u + | ||
91 | ((unsigned char const*) p) [0]; | ||
92 | } | ||
93 | |||
94 | static inline int get_le16s( void const* p ) | ||
95 | { | ||
96 | return ((signed char const*) p) [1] * 0x100 + | ||
97 | ((unsigned char const*) p) [0]; | ||
98 | } | ||
99 | |||
100 | static inline void set_le16( void* p, unsigned n ) | ||
101 | { | ||
102 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); | ||
103 | ((unsigned char*) p) [0] = (unsigned char) n; | ||
104 | } | ||
105 | |||
106 | #define GET_LE16( addr ) get_le16( addr ) | ||
107 | #define SET_LE16( addr, data ) set_le16( addr, data ) | ||
108 | #define INT16A( addr ) (*(uint16_t*) (addr)) | ||
109 | #define INT16SA( addr ) (*(int16_t*) (addr)) | ||
110 | |||
111 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
112 | #define GET_LE16A( addr ) (*(uint16_t*) (addr)) | ||
113 | #define GET_LE16SA( addr ) (*( int16_t*) (addr)) | ||
114 | #define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data)) | ||
115 | #else | ||
116 | #define GET_LE16A( addr ) get_le16 ( addr ) | ||
117 | #define GET_LE16SA( addr ) get_le16s( addr ) | ||
118 | #define SET_LE16A( addr, data ) set_le16 ( addr, data ) | ||
119 | #endif | ||
120 | |||
121 | static struct | ||
122 | { | ||
123 | union { | ||
124 | uint8_t padding1 [0x100]; | ||
125 | uint16_t align; | ||
126 | } padding1 [1]; | ||
127 | uint8_t ram [0x10000]; | ||
128 | uint8_t padding2 [0x100]; | ||
129 | } ram; | ||
130 | |||
131 | #include "spc/Spc_Dsp.h" | ||
132 | |||
133 | #undef RAM | ||
134 | #define RAM ram.ram | ||
135 | |||
136 | /**************** Timers ****************/ | ||
137 | |||
138 | enum { timer_count = 3 }; | ||
139 | |||
140 | struct Timer | ||
141 | { | ||
142 | long next_tick; | ||
143 | int period; | ||
144 | int count; | ||
145 | int shift; | ||
146 | int enabled; | ||
147 | int counter; | ||
148 | }; | ||
149 | |||
150 | static void Timer_run_( struct Timer* t, long time ) ICODE_ATTR; | ||
151 | static void Timer_run_( struct Timer* t, long time ) | ||
152 | { | ||
153 | /* when disabled, next_tick should always be in the future */ | ||
154 | assert( t->enabled ); | ||
155 | |||
156 | int elapsed = ((time - t->next_tick) >> t->shift) + 1; | ||
157 | t->next_tick += elapsed << t->shift; | ||
158 | |||
159 | elapsed += t->count; | ||
160 | if ( elapsed >= t->period ) /* avoid unnecessary division */ | ||
161 | { | ||
162 | int n = elapsed / t->period; | ||
163 | elapsed -= n * t->period; | ||
164 | t->counter = (t->counter + n) & 15; | ||
165 | } | ||
166 | t->count = elapsed; | ||
167 | } | ||
168 | |||
169 | static inline void Timer_run( struct Timer* t, long time ) | ||
170 | { | ||
171 | if ( time >= t->next_tick ) | ||
172 | Timer_run_( t, time ); | ||
173 | } | ||
174 | |||
175 | /**************** SPC emulator ****************/ | ||
176 | /* 1.024 MHz clock / 32000 samples per second */ | ||
177 | enum { clocks_per_sample = 32 }; | ||
178 | |||
179 | enum { extra_clocks = clocks_per_sample / 2 }; | ||
180 | |||
181 | /* using this disables timer (since this will always be in the future) */ | ||
182 | enum { timer_disabled_time = 127 }; | ||
183 | |||
184 | enum { rom_size = 64 }; | ||
185 | enum { rom_addr = 0xFFC0 }; | ||
186 | |||
187 | struct cpu_regs_t | ||
188 | { | ||
189 | long pc; /* more than 16 bits to allow overflow detection */ | ||
190 | uint8_t a; | ||
191 | uint8_t x; | ||
192 | uint8_t y; | ||
193 | uint8_t status; | ||
194 | uint8_t sp; | ||
195 | }; | ||
196 | |||
197 | |||
198 | struct Spc_Emu | ||
199 | { | ||
200 | uint8_t cycle_table [0x100]; | ||
201 | struct cpu_regs_t r; | ||
202 | |||
203 | int32_t* sample_buf; | ||
204 | long next_dsp; | ||
205 | int rom_enabled; | ||
206 | int extra_cycles; | ||
207 | |||
208 | struct Timer timer [timer_count]; | ||
209 | |||
210 | /* large objects at end */ | ||
211 | struct Spc_Dsp dsp; | ||
212 | uint8_t extra_ram [rom_size]; | ||
213 | uint8_t boot_rom [rom_size]; | ||
214 | }; | ||
215 | |||
216 | static void SPC_enable_rom( THIS, int enable ) | ||
217 | { | ||
218 | if ( this->rom_enabled != enable ) | ||
219 | { | ||
220 | this->rom_enabled = enable; | ||
221 | memcpy( RAM + rom_addr, (enable ? this->boot_rom : this->extra_ram), rom_size ); | ||
222 | /* TODO: ROM can still get overwritten when DSP writes to echo buffer */ | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static void SPC_Init( THIS ) | ||
227 | { | ||
228 | this->timer [0].shift = 4 + 3; /* 8 kHz */ | ||
229 | this->timer [1].shift = 4 + 3; /* 8 kHz */ | ||
230 | this->timer [2].shift = 4; /* 8 kHz */ | ||
231 | |||
232 | /* Put STOP instruction around memory to catch PC underflow/overflow. */ | ||
233 | memset( ram.padding1, 0xFF, sizeof ram.padding1 ); | ||
234 | memset( ram.padding2, 0xFF, sizeof ram.padding2 ); | ||
235 | |||
236 | /* A few tracks read from the last four bytes of IPL ROM */ | ||
237 | this->boot_rom [sizeof this->boot_rom - 2] = 0xC0; | ||
238 | this->boot_rom [sizeof this->boot_rom - 1] = 0xFF; | ||
239 | memset( this->boot_rom, 0, sizeof this->boot_rom - 2 ); | ||
240 | } | ||
241 | |||
242 | static void SPC_load_state( THIS, struct cpu_regs_t const* cpu_state, | ||
243 | const void* new_ram, const void* dsp_state ) | ||
244 | { | ||
245 | memcpy(&(this->r),cpu_state,sizeof this->r); | ||
246 | |||
247 | /* ram */ | ||
248 | memcpy( RAM, new_ram, sizeof RAM ); | ||
249 | memcpy( this->extra_ram, RAM + rom_addr, sizeof this->extra_ram ); | ||
250 | |||
251 | /* boot rom (have to force enable_rom() to update it) */ | ||
252 | this->rom_enabled = !(RAM [0xF1] & 0x80); | ||
253 | SPC_enable_rom( this, !this->rom_enabled ); | ||
254 | |||
255 | /* dsp */ | ||
256 | /* some SPCs rely on DSP immediately generating one sample */ | ||
257 | this->extra_cycles = 32; | ||
258 | DSP_reset( &this->dsp ); | ||
259 | int i; | ||
260 | for ( i = 0; i < register_count; i++ ) | ||
261 | DSP_write( &this->dsp, i, ((uint8_t const*) dsp_state) [i] ); | ||
262 | |||
263 | /* timers */ | ||
264 | for ( i = 0; i < timer_count; i++ ) | ||
265 | { | ||
266 | struct Timer* t = &this->timer [i]; | ||
267 | |||
268 | t->next_tick = -extra_clocks; | ||
269 | t->enabled = (RAM [0xF1] >> i) & 1; | ||
270 | if ( !t->enabled ) | ||
271 | t->next_tick = timer_disabled_time; | ||
272 | t->count = 0; | ||
273 | t->counter = RAM [0xFD + i] & 15; | ||
274 | |||
275 | int p = RAM [0xFA + i]; | ||
276 | if ( !p ) | ||
277 | p = 0x100; | ||
278 | t->period = p; | ||
279 | } | ||
280 | |||
281 | /* Handle registers which already give 0 when read by | ||
282 | setting RAM and not changing it. | ||
283 | Put STOP instruction in registers which can be read, | ||
284 | to catch attempted execution. */ | ||
285 | RAM [0xF0] = 0; | ||
286 | RAM [0xF1] = 0; | ||
287 | RAM [0xF3] = 0xFF; | ||
288 | RAM [0xFA] = 0; | ||
289 | RAM [0xFB] = 0; | ||
290 | RAM [0xFC] = 0; | ||
291 | RAM [0xFD] = 0xFF; | ||
292 | RAM [0xFE] = 0xFF; | ||
293 | RAM [0xFF] = 0xFF; | ||
294 | } | ||
295 | |||
296 | static void clear_echo( THIS ) | ||
297 | { | ||
298 | if ( !(DSP_read( &this->dsp, 0x6C ) & 0x20) ) | ||
299 | { | ||
300 | unsigned addr = 0x100 * DSP_read( &this->dsp, 0x6D ); | ||
301 | size_t size = 0x800 * DSP_read( &this->dsp, 0x7D ); | ||
302 | size_t max_size = sizeof RAM - addr; | ||
303 | if ( size > max_size ) | ||
304 | size = sizeof RAM - addr; | ||
305 | memset( RAM + addr, 0xFF, size ); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | enum { spc_file_size = 0x10180 }; | ||
310 | |||
311 | struct spc_file_t | ||
312 | { | ||
313 | char signature [27]; | ||
314 | char unused [10]; | ||
315 | uint8_t pc [2]; | ||
316 | uint8_t a; | ||
317 | uint8_t x; | ||
318 | uint8_t y; | ||
319 | uint8_t status; | ||
320 | uint8_t sp; | ||
321 | char unused2 [212]; | ||
322 | uint8_t ram [0x10000]; | ||
323 | uint8_t dsp [128]; | ||
324 | uint8_t ipl_rom [128]; | ||
325 | }; | ||
326 | |||
327 | static int SPC_load_spc( THIS, const void* data, long size ) | ||
328 | { | ||
329 | struct spc_file_t const* spc = (struct spc_file_t const*) data; | ||
330 | struct cpu_regs_t regs; | ||
331 | |||
332 | if ( size < spc_file_size ) | ||
333 | return -1; | ||
334 | |||
335 | if ( memcmp( spc->signature, "SNES-SPC700 Sound File Data", 27 ) != 0 ) | ||
336 | return -1; | ||
337 | |||
338 | regs.pc = spc->pc [1] * 0x100 + spc->pc [0]; | ||
339 | regs.a = spc->a; | ||
340 | regs.x = spc->x; | ||
341 | regs.y = spc->y; | ||
342 | regs.status = spc->status; | ||
343 | regs.sp = spc->sp; | ||
344 | |||
345 | if ( (unsigned long) size >= sizeof *spc ) | ||
346 | memcpy( this->boot_rom, spc->ipl_rom, sizeof this->boot_rom ); | ||
347 | |||
348 | SPC_load_state( this, ®s, spc->ram, spc->dsp ); | ||
349 | |||
350 | clear_echo(this); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /**************** DSP interaction ****************/ | ||
356 | |||
357 | static void SPC_run_dsp_( THIS, long time ) ICODE_ATTR; | ||
358 | static void SPC_run_dsp_( THIS, long time ) | ||
359 | { | ||
360 | /* divide by clocks_per_sample */ | ||
361 | int count = ((time - this->next_dsp) >> 5) + 1; | ||
362 | int32_t* buf = this->sample_buf; | ||
363 | this->sample_buf = buf + count; | ||
364 | this->next_dsp += count * clocks_per_sample; | ||
365 | DSP_run( &this->dsp, count, buf ); | ||
366 | } | ||
367 | |||
368 | static inline void SPC_run_dsp( THIS, long time ) | ||
369 | { | ||
370 | if ( time >= this->next_dsp ) | ||
371 | SPC_run_dsp_( this, time ); | ||
372 | } | ||
373 | |||
374 | static int SPC_read( THIS, unsigned addr, long const time ) ICODE_ATTR; | ||
375 | static int SPC_read( THIS, unsigned addr, long const time ) | ||
376 | { | ||
377 | int result = RAM [addr]; | ||
378 | |||
379 | if ( ((unsigned) (addr - 0xF0)) < 0x10 ) | ||
380 | { | ||
381 | assert( 0xF0 <= addr && addr <= 0xFF ); | ||
382 | |||
383 | /* counters */ | ||
384 | int i = addr - 0xFD; | ||
385 | if ( i >= 0 ) | ||
386 | { | ||
387 | struct Timer* t = &this->timer [i]; | ||
388 | Timer_run( t, time ); | ||
389 | result = t->counter; | ||
390 | t->counter = 0; | ||
391 | } | ||
392 | /* dsp */ | ||
393 | else if ( addr == 0xF3 ) | ||
394 | { | ||
395 | SPC_run_dsp( this, time ); | ||
396 | result = DSP_read( &this->dsp, RAM [0xF2] & 0x7F ); | ||
397 | } | ||
398 | } | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | static void SPC_write( THIS, unsigned addr, int data, long const time ) | ||
403 | ICODE_ATTR; | ||
404 | static void SPC_write( THIS, unsigned addr, int data, long const time ) | ||
405 | { | ||
406 | /* first page is very common */ | ||
407 | if ( addr < 0xF0 ) | ||
408 | { | ||
409 | RAM [addr] = (uint8_t) data; | ||
410 | } | ||
411 | else switch ( addr ) | ||
412 | { | ||
413 | /* RAM */ | ||
414 | default: | ||
415 | if ( addr < rom_addr ) | ||
416 | { | ||
417 | RAM [addr] = (uint8_t) data; | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | this->extra_ram [addr - rom_addr] = (uint8_t) data; | ||
422 | if ( !this->rom_enabled ) | ||
423 | RAM [addr] = (uint8_t) data; | ||
424 | } | ||
425 | break; | ||
426 | |||
427 | /* DSP */ | ||
428 | /*case 0xF2:*/ /* mapped to RAM */ | ||
429 | case 0xF3: { | ||
430 | SPC_run_dsp( this, time ); | ||
431 | int reg = RAM [0xF2]; | ||
432 | if ( reg < register_count ) { | ||
433 | DSP_write( &this->dsp, reg, data ); | ||
434 | } | ||
435 | else { | ||
436 | /*dprintf( "DSP write to $%02X\n", (int) reg ); */ | ||
437 | } | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | case 0xF0: /* Test register */ | ||
442 | /*dprintf( "Wrote $%02X to $F0\n", (int) data ); */ | ||
443 | break; | ||
444 | |||
445 | /* Config */ | ||
446 | case 0xF1: | ||
447 | { | ||
448 | int i; | ||
449 | /* timers */ | ||
450 | for ( i = 0; i < timer_count; i++ ) | ||
451 | { | ||
452 | struct Timer * t = this->timer+i; | ||
453 | if ( !(data & (1 << i)) ) | ||
454 | { | ||
455 | t->enabled = 0; | ||
456 | t->next_tick = timer_disabled_time; | ||
457 | } | ||
458 | else if ( !t->enabled ) | ||
459 | { | ||
460 | /* just enabled */ | ||
461 | t->enabled = 1; | ||
462 | t->counter = 0; | ||
463 | t->count = 0; | ||
464 | t->next_tick = time; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | /* port clears */ | ||
469 | if ( data & 0x10 ) | ||
470 | { | ||
471 | RAM [0xF4] = 0; | ||
472 | RAM [0xF5] = 0; | ||
473 | } | ||
474 | if ( data & 0x20 ) | ||
475 | { | ||
476 | RAM [0xF6] = 0; | ||
477 | RAM [0xF7] = 0; | ||
478 | } | ||
479 | |||
480 | SPC_enable_rom( this, (data & 0x80) != 0 ); | ||
481 | break; | ||
482 | } | ||
483 | |||
484 | /* Ports */ | ||
485 | case 0xF4: | ||
486 | case 0xF5: | ||
487 | case 0xF6: | ||
488 | case 0xF7: | ||
489 | /* to do: handle output ports */ | ||
490 | break; | ||
491 | |||
492 | /* verified on SNES that these are read/write (RAM) */ | ||
493 | /*case 0xF8: */ | ||
494 | /*case 0xF9: */ | ||
495 | |||
496 | /* Timers */ | ||
497 | case 0xFA: | ||
498 | case 0xFB: | ||
499 | case 0xFC: { | ||
500 | int i = addr - 0xFA; | ||
501 | struct Timer* t = &this->timer [i]; | ||
502 | if ( (t->period & 0xFF) != data ) | ||
503 | { | ||
504 | Timer_run( t, time ); | ||
505 | this->timer[i].period = data ? data : 0x100; | ||
506 | } | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | /* Counters (cleared on write) */ | ||
511 | case 0xFD: | ||
512 | case 0xFE: | ||
513 | case 0xFF: | ||
514 | /*dprintf( "Wrote to counter $%02X\n", (int) addr ); */ | ||
515 | this->timer [addr - 0xFD].counter = 0; | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | #include "spc/Spc_Cpu.h" | ||
521 | |||
522 | /**************** Sample generation ****************/ | ||
523 | |||
524 | static int SPC_play( THIS, long count, int32_t* out ) ICODE_ATTR; | ||
525 | static int SPC_play( THIS, long count, int32_t* out ) | ||
526 | { | ||
527 | int i; | ||
528 | assert( count % 2 == 0 ); /* output is always in pairs of samples */ | ||
529 | |||
530 | long start_time = -(count >> 1) * clocks_per_sample - extra_clocks; | ||
531 | |||
532 | /* DSP output is made on-the-fly when DSP registers are read or written */ | ||
533 | this->sample_buf = out; | ||
534 | this->next_dsp = start_time + clocks_per_sample; | ||
535 | |||
536 | /* Localize timer next_tick times and run them to the present to prevent | ||
537 | a running but ignored timer's next_tick from getting too far behind | ||
538 | and overflowing. */ | ||
539 | for ( i = 0; i < timer_count; i++ ) | ||
540 | { | ||
541 | struct Timer* t = &this->timer [i]; | ||
542 | if ( t->enabled ) | ||
543 | { | ||
544 | t->next_tick += start_time + extra_clocks; | ||
545 | Timer_run( t, start_time ); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | /* Run from start_time to 0, pre-advancing by extra cycles from last run */ | ||
550 | this->extra_cycles = CPU_run( this, start_time + this->extra_cycles ) + | ||
551 | extra_clocks; | ||
552 | if ( this->extra_cycles < 0 ) | ||
553 | { | ||
554 | /*dprintf( "Unhandled instruction $%02X, pc = $%04X\n", | ||
555 | (int) CPU_read( r.pc ), (unsigned) r.pc ); */ | ||
556 | |||
557 | return -1; | ||
558 | } | ||
559 | |||
560 | /* Catch DSP up to present */ | ||
561 | #if 0 | ||
562 | ENTER_TIMER(cpu); | ||
563 | #endif | ||
564 | SPC_run_dsp( this, -extra_clocks ); | ||
565 | #if 0 | ||
566 | EXIT_TIMER(cpu); | ||
567 | #endif | ||
568 | assert( this->next_dsp == clocks_per_sample - extra_clocks ); | ||
569 | assert( this->sample_buf - out == count ); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | 30 | ||
574 | /**************** ID666 parsing ****************/ | 31 | /**************** ID666 parsing ****************/ |
575 | 32 | ||
@@ -733,15 +190,15 @@ static int32_t samples[WAV_CHUNK_SIZE*2] IBSS_ATTR; | |||
733 | 190 | ||
734 | static struct Spc_Emu spc_emu IDATA_ATTR; | 191 | static struct Spc_Emu spc_emu IDATA_ATTR; |
735 | 192 | ||
736 | enum {sample_rate = 32000}; | 193 | enum {SAMPLE_RATE = 32000}; |
737 | 194 | ||
738 | /* The main decoder loop */ | 195 | /* The main decoder loop */ |
739 | static int play_track( void ) | 196 | static int play_track( void ) |
740 | { | 197 | { |
741 | int sampleswritten=0; | 198 | int sampleswritten=0; |
742 | 199 | ||
743 | unsigned long fadestartsample = ID666.length*(long long) sample_rate/1000; | 200 | unsigned long fadestartsample = ID666.length*(long long) SAMPLE_RATE/1000; |
744 | unsigned long fadeendsample = (ID666.length+ID666.fade)*(long long) sample_rate/1000; | 201 | unsigned long fadeendsample = (ID666.length+ID666.fade)*(long long) SAMPLE_RATE/1000; |
745 | int fadedec = 0; | 202 | int fadedec = 0; |
746 | int fadevol = 0x7fffffffl; | 203 | int fadevol = 0x7fffffffl; |
747 | 204 | ||
@@ -758,7 +215,7 @@ static int play_track( void ) | |||
758 | } | 215 | } |
759 | 216 | ||
760 | if (ci->seek_time) { | 217 | if (ci->seek_time) { |
761 | int curtime = sampleswritten*1000LL/sample_rate; | 218 | int curtime = sampleswritten*1000LL/SAMPLE_RATE; |
762 | DEBUGF("seek to %ld\ncurrently at %d\n",ci->seek_time,curtime); | 219 | DEBUGF("seek to %ld\ncurrently at %d\n",ci->seek_time,curtime); |
763 | if (ci->seek_time < curtime) { | 220 | if (ci->seek_time < curtime) { |
764 | DEBUGF("seek backwards = reset\n"); | 221 | DEBUGF("seek backwards = reset\n"); |
@@ -778,7 +235,7 @@ static int play_track( void ) | |||
778 | 235 | ||
779 | /* is track timed? */ | 236 | /* is track timed? */ |
780 | if (ci->global_settings->repeat_mode!=REPEAT_ONE && ci->id3->length) { | 237 | if (ci->global_settings->repeat_mode!=REPEAT_ONE && ci->id3->length) { |
781 | unsigned long curtime = sampleswritten*1000LL/sample_rate; | 238 | unsigned long curtime = sampleswritten*1000LL/SAMPLE_RATE; |
782 | unsigned long lasttimesample = (sampleswritten-WAV_CHUNK_SIZE); | 239 | unsigned long lasttimesample = (sampleswritten-WAV_CHUNK_SIZE); |
783 | 240 | ||
784 | /* fade? */ | 241 | /* fade? */ |
@@ -811,7 +268,7 @@ static int play_track( void ) | |||
811 | ci->pcmbuf_insert(samples, samples+WAV_CHUNK_SIZE, WAV_CHUNK_SIZE); | 268 | ci->pcmbuf_insert(samples, samples+WAV_CHUNK_SIZE, WAV_CHUNK_SIZE); |
812 | 269 | ||
813 | if (ci->global_settings->repeat_mode!=REPEAT_ONE) | 270 | if (ci->global_settings->repeat_mode!=REPEAT_ONE) |
814 | ci->set_elapsed(sampleswritten*1000LL/sample_rate); | 271 | ci->set_elapsed(sampleswritten*1000LL/SAMPLE_RATE); |
815 | else | 272 | else |
816 | ci->set_elapsed(0); | 273 | ci->set_elapsed(0); |
817 | } | 274 | } |
@@ -824,11 +281,11 @@ static int play_track( void ) | |||
824 | /* this is the codec entry point */ | 281 | /* this is the codec entry point */ |
825 | enum codec_status codec_main(void) | 282 | enum codec_status codec_main(void) |
826 | { | 283 | { |
827 | memcpy( spc_emu.cycle_table, cycle_table, sizeof cycle_table ); | ||
828 | |||
829 | #ifdef CPU_COLDFIRE | 284 | #ifdef CPU_COLDFIRE |
285 | /* signed integer mode with saturation */ | ||
830 | coldfire_set_macsr(EMAC_SATURATE); | 286 | coldfire_set_macsr(EMAC_SATURATE); |
831 | #endif | 287 | #endif |
288 | CPU_Init(&spc_emu); | ||
832 | 289 | ||
833 | do | 290 | do |
834 | { | 291 | { |
@@ -839,7 +296,7 @@ enum codec_status codec_main(void) | |||
839 | DEBUGF("SPC: after init\n"); | 296 | DEBUGF("SPC: after init\n"); |
840 | 297 | ||
841 | ci->configure(DSP_SET_SAMPLE_DEPTH, 24); | 298 | ci->configure(DSP_SET_SAMPLE_DEPTH, 24); |
842 | ci->configure(DSP_SET_FREQUENCY, sample_rate); | 299 | ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE); |
843 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); | 300 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); |
844 | 301 | ||
845 | /* wait for track info to load */ | 302 | /* wait for track info to load */ |