1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007-2008 Michael Sevakis (jhMikeS)
11 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
12 * Copyright (C) 2004-2007 Shay Green (blargg)
13 * Copyright (C) 2002 Brad Martin
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
25 /* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
26 /* DSP Based on Brad Martin's OpenSPC DSP emulator */
27 /* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */
29 #include "../fracmul.h"
30 #include "libspc/spc_codec.h"
31 #include "libspc/spc_profiler.h"
35 /**************** ID666 parsing ****************/
38 unsigned char isBinary
;
48 unsigned char emulator
;
51 static int LoadID666(unsigned char *buf
) {
52 unsigned char *ib
=buf
;
56 memcpy(ID666
.song
,ib
,32);
60 memcpy(ID666
.game
,ib
,32);
64 memcpy(ID666
.dumper
,ib
,16);
68 memcpy(ID666
.comments
,ib
,32);
72 /* Ok, now comes the fun part. */
75 if(ib
[2] == '/' && ib
[5] == '/' )
78 /* Reserved bytes check */
79 if(ib
[0xD2 - 0x2E - 112] >= '0' &&
80 ib
[0xD2 - 0x2E - 112] <= '9' &&
81 ib
[0xD3 - 0x2E - 112] == 0x00)
84 /* is length & fade only digits? */
86 (ib
[0xA9 - 0x2E - 112+i
]>='0'&&ib
[0xA9 - 0x2E - 112+i
]<='9') ||
87 ib
[0xA9 - 0x2E - 112+i
]=='\0');
91 ID666
.isBinary
= isbinary
;
94 DEBUGF("binary tag detected\n");
109 ID666
.length
|=*ib
<<8;
112 ID666
.length
|=*ib
<<16;
125 memcpy(ID666
.artist
,ib
,32);
138 DEBUGF("text tag detected\n");
143 for (i
=0;i
<2 && buf
[i
]>='0' && buf
[i
]<='9';i
++) tmp
=tmp
*10+buf
[i
]-'0';
150 for (i
=0;i
<2 && buf
[i
]>='0' && buf
[i
]<='9';i
++) tmp
=tmp
*10+buf
[i
]-'0';
157 for (i
=0;i
<4 && buf
[i
]>='0' && buf
[i
]<='9';i
++) tmp
=tmp
*10+buf
[i
]-'0';
164 for (i
=0;i
<3 && buf
[i
]>='0' && buf
[i
]<='9';i
++) tmp
=tmp
*10+buf
[i
]-'0';
165 ID666
.length
= tmp
* 1000;
171 for (i
=0;i
<5 && buf
[i
]>='0' && buf
[i
]<='9';i
++) tmp
=tmp
*10+buf
[i
]-'0';
175 memcpy(ID666
.artist
,ib
,32);
179 /*I have no idea if this is right or not.*/
191 /**************** Codec ****************/
192 enum {SAMPLE_RATE
= 32000};
193 static struct Spc_Emu spc_emu IBSS_ATTR_SPC CACHEALIGN_ATTR
;
196 /** Implementations for pipelined dual-core operation **/
197 static int spc_emu_thread_stack
[DEFAULT_STACK_SIZE
/sizeof(int)]
200 static const unsigned char * const spc_emu_thread_name
= "spc emu";
201 static unsigned int emu_thread_id
= 0;
217 #define WAV_NUM_CHUNKS 2
218 #define WAV_CHUNK_MASK (WAV_NUM_CHUNKS-1)
219 struct sample_queue_chunk
225 int32_t audio
[WAV_CHUNK_SIZE
*2];
232 struct semaphore emu_sem_head
;
233 struct semaphore emu_sem_tail
;
234 struct semaphore emu_evt_reply
;
236 struct sample_queue_chunk wav_chunk
[WAV_NUM_CHUNKS
];
237 } sample_queue SHAREDBSS_ATTR
;
239 static inline void samples_release_wrbuf(void)
242 ci
->semaphore_release(&sample_queue
.emu_sem_head
);
245 static inline struct sample_queue_chunk
* samples_get_wrbuf(void)
247 ci
->semaphore_wait(&sample_queue
.emu_sem_tail
, TIMEOUT_BLOCK
);
248 return &sample_queue
.wav_chunk
[sample_queue
.tail
& WAV_CHUNK_MASK
];
251 static inline void samples_release_rdbuf(void)
253 if (sample_queue
.head
!= sample_queue
.tail
) {
257 ci
->semaphore_release(&sample_queue
.emu_sem_tail
);
260 static inline int32_t * samples_get_rdbuf(void)
262 ci
->semaphore_wait(&sample_queue
.emu_sem_head
, TIMEOUT_BLOCK
);
263 return sample_queue
.wav_chunk
[sample_queue
.head
& WAV_CHUNK_MASK
].audio
;
266 static intptr_t emu_thread_send_msg(long id
, intptr_t data
)
268 struct sample_queue_chunk
*chunk
;
269 /* Grab an audio output buffer */
270 ci
->semaphore_wait(&sample_queue
.emu_sem_head
, TIMEOUT_BLOCK
);
271 chunk
= &sample_queue
.wav_chunk
[sample_queue
.head
& WAV_CHUNK_MASK
];
272 /* Place a message in it instead of audio */
275 /* Release it to the emu thread */
276 samples_release_rdbuf();
278 if (id
!= SPC_EMU_QUIT
) {
279 /* Wait for a response */
280 ci
->semaphore_wait(&sample_queue
.emu_evt_reply
, TIMEOUT_BLOCK
);
283 return sample_queue
.retval
;
286 /* thread function */
287 static bool emu_thread_process_msg(struct sample_queue_chunk
*chunk
)
290 bool ret
= id
!= SPC_EMU_QUIT
;
292 chunk
->id
= SPC_EMU_AUDIO
; /* Reset chunk type to audio */
293 sample_queue
.retval
= 0;
295 if (id
== SPC_EMU_LOAD
)
297 struct spc_load
*ld
= (struct spc_load
*)chunk
->data
;
298 ci
->cpucache_invalidate();
300 sample_queue
.retval
= SPC_load_spc(&spc_emu
, ld
->buf
, ld
->size
);
302 /* Empty the audio queue */
303 ci
->semaphore_release(&sample_queue
.emu_sem_tail
);
304 ci
->semaphore_release(&sample_queue
.emu_sem_tail
);
305 ci
->semaphore_wait(&sample_queue
.emu_sem_head
, TIMEOUT_NOBLOCK
);
306 ci
->semaphore_wait(&sample_queue
.emu_sem_head
, TIMEOUT_NOBLOCK
);
307 sample_queue
.head
= sample_queue
.tail
= 0;
310 if (id
!= SPC_EMU_QUIT
) {
311 ci
->semaphore_release(&sample_queue
.emu_evt_reply
);
317 static void spc_emu_thread(void)
322 /* get a buffer for output */
323 struct sample_queue_chunk
*chunk
= samples_get_wrbuf();
325 if (chunk
->id
!= SPC_EMU_AUDIO
) {
326 /* This chunk doesn't contain audio but a command */
327 if (!emu_thread_process_msg(chunk
))
329 /* Have to re-get this pointer to keep semaphore counts correct */
334 /* fill samples buffer */
335 if ( SPC_play(&spc_emu
, WAV_CHUNK_SIZE
*2, chunk
->audio
) )
339 /* done so release it to output */
340 samples_release_wrbuf();
345 static bool spc_emu_start(void)
347 emu_thread_id
= ci
->create_thread(spc_emu_thread
, spc_emu_thread_stack
,
348 sizeof(spc_emu_thread_stack
), CREATE_THREAD_FROZEN
,
349 spc_emu_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
), COP
);
351 if (emu_thread_id
== 0)
354 /* Initialize audio queue as full to prevent emu thread from trying to run the
355 emulator before loading something */
356 ci
->semaphore_init(&sample_queue
.emu_evt_reply
, 1, 0);
357 ci
->semaphore_init(&sample_queue
.emu_sem_tail
, 2, 0);
358 ci
->semaphore_init(&sample_queue
.emu_sem_head
, 2, 2);
359 sample_queue
.head
= 0;
360 sample_queue
.tail
= 2;
362 /* Start it running */
363 ci
->thread_thaw(emu_thread_id
);
367 /* load a new program on the emu thread */
368 static inline int load_spc_buffer(uint8_t *buf
, size_t size
)
370 struct spc_load ld
= { buf
, size
};
371 ci
->cpucache_flush();
372 return emu_thread_send_msg(SPC_EMU_LOAD
, (intptr_t)&ld
);
375 static inline void spc_emu_quit(void)
377 if (emu_thread_id
!= 0) {
378 emu_thread_send_msg(SPC_EMU_QUIT
, 0);
379 /* Wait for emu thread to be killed */
380 ci
->thread_wait(emu_thread_id
);
381 ci
->cpucache_invalidate();
385 static inline int32_t * spc_play_get_samples(void)
387 /* obtain filled samples buffer */
388 return samples_get_rdbuf();
391 static inline void spc_play_send_samples(int32_t *samples
)
393 ci
->pcmbuf_insert(samples
, samples
+WAV_CHUNK_SIZE
, WAV_CHUNK_SIZE
);
394 /* done with chunk so release it to emu thread */
395 samples_release_rdbuf();
398 #else /* !SPC_DUAL_CORE */
399 /** Implementations for single-core operation **/
400 static int32_t wav_chunk
[WAV_CHUNK_SIZE
*2] IBSS_ATTR
;
402 /* load a new program into emu */
403 static inline int load_spc_buffer(uint8_t *buf
, size_t size
)
406 return SPC_load_spc(&spc_emu
, buf
, size
);
409 static inline bool spc_emu_start(void)
412 /* signed integer mode with saturation */
413 coldfire_set_macsr(EMAC_SATURATE
);
419 static inline void spc_play_send_samples(int32_t *samples
)
421 ci
->pcmbuf_insert(samples
, samples
+WAV_CHUNK_SIZE
, WAV_CHUNK_SIZE
);
424 #define spc_emu_quit()
425 #define samples_release_rdbuf()
427 static inline int32_t * spc_play_get_samples(void)
430 /* fill samples buffer */
431 if ( SPC_play(&spc_emu
,WAV_CHUNK_SIZE
*2,wav_chunk
) )
436 #endif /* SPC_DUAL_CORE */
438 /* The main decoder loop */
439 static int play_track( void )
441 int sampleswritten
=0;
443 unsigned long fadestartsample
= ID666
.length
*(long long) SAMPLE_RATE
/1000;
444 unsigned long fadeendsample
= (ID666
.length
+ID666
.fade
)*(long long) SAMPLE_RATE
/1000;
446 int fadevol
= 0x7fffffffl
;
449 if (fadeendsample
>fadestartsample
)
450 fadedec
=0x7fffffffl
/(fadeendsample
-fadestartsample
)+1;
456 enum codec_command_action action
= ci
->get_command(¶m
);
458 if (action
== CODEC_ACTION_HALT
)
461 if (action
== CODEC_ACTION_SEEK_TIME
) {
462 int curtime
= sampleswritten
*1000LL/SAMPLE_RATE
;
463 DEBUGF("seek to %ld\ncurrently at %d\n", (long)param
, curtime
);
464 if (param
< curtime
) {
465 DEBUGF("seek backwards = reset\n");
471 ci
->set_elapsed(curtime
);
475 int32_t *samples
= spc_play_get_samples();
477 sampleswritten
+= WAV_CHUNK_SIZE
;
479 /* is track timed? */
480 if (ci
->global_settings
->repeat_mode
!=REPEAT_ONE
&& ci
->id3
->length
) {
481 unsigned long curtime
= sampleswritten
*1000LL/SAMPLE_RATE
;
482 unsigned long lasttimesample
= (sampleswritten
-WAV_CHUNK_SIZE
);
485 if (curtime
>ID666
.length
)
488 /* Have to switch modes to do this */
489 long macsr
= coldfire_get_macsr();
490 coldfire_set_macsr(EMAC_SATURATE
| EMAC_FRACTIONAL
| EMAC_ROUND
);
493 for (i
=0;i
<WAV_CHUNK_SIZE
;i
++) {
494 if (lasttimesample
+i
>fadestartsample
) {
496 samples
[i
] = FRACMUL(samples
[i
], fadevol
);
497 samples
[i
+WAV_CHUNK_SIZE
] = FRACMUL(samples
[i
+WAV_CHUNK_SIZE
], fadevol
);
498 } else samples
[i
]=samples
[i
+WAV_CHUNK_SIZE
]=0;
503 coldfire_set_macsr(macsr
);
507 if (lasttimesample
>=fadeendsample
)
509 samples_release_rdbuf();
514 spc_play_send_samples(samples
);
516 if (ci
->global_settings
->repeat_mode
!=REPEAT_ONE
)
517 ci
->set_elapsed(sampleswritten
*1000LL/SAMPLE_RATE
);
526 /* this is the codec entry point */
527 enum codec_status
codec_main(enum codec_entry_call_reason reason
)
529 if (reason
== CODEC_LOAD
) {
530 if (!spc_emu_start())
533 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 24);
534 ci
->configure(DSP_SET_FREQUENCY
, SAMPLE_RATE
);
535 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_NONINTERLEAVED
);
537 else if (reason
== CODEC_UNLOAD
) {
544 /* this is called for each file to process */
545 enum codec_status
codec_run(void)
547 DEBUGF("SPC: next_track\n");
550 DEBUGF("SPC: after init\n");
552 codec_set_replaygain(ci
->id3
);
554 /* Read the entire file */
555 DEBUGF("SPC: request initial buffer\n");
558 uint8_t* buffer
= ci
->request_buffer(&buffersize
, ci
->filesize
);
562 DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize
);
565 if (load_spc_buffer(buffer
, buffersize
)) {
566 DEBUGF("SPC load failure\n");
570 LoadID666(buffer
+0x2e);
572 if (ci
->global_settings
->repeat_mode
!=REPEAT_ONE
&& ID666
.length
==0) {
573 ID666
.length
=3*60*1000; /* 3 minutes */
574 ID666
.fade
=5*1000; /* 5 seconds */
577 reset_profile_timers();
579 while ( play_track() );
581 print_timers(ci
->id3
->path
);