diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-09-23 08:09:04 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-09-23 08:09:04 +0000 |
commit | 5c903724fbc930d57d4e07a719d4abfd65dec593 (patch) | |
tree | c3f4e1a81e2035aaa57bfdbac7c7a1efe35b1041 /apps/codecs | |
parent | b95dbd21cf79940a02ef9f95d8914b7f439f2891 (diff) | |
download | rockbox-5c903724fbc930d57d4e07a719d4abfd65dec593.tar.gz rockbox-5c903724fbc930d57d4e07a719d4abfd65dec593.zip |
Simplify synchronizaton for MPA codec and make it fully atomic, let synth thread exist for life of codec, do a bit of cleanup and use number of cores do determine if it is compiled as multithread instead of CPU type.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18573 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs')
-rw-r--r-- | apps/codecs/mpa.c | 144 |
1 files changed, 72 insertions, 72 deletions
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index e81d8d96c0..f998412de1 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | CODEC_HEADER | 26 | CODEC_HEADER |
27 | 27 | ||
28 | #if defined(CPU_PP) && !defined(MPEGPLAYER) | 28 | #if NUM_CORES > 1 && !defined(MPEGPLAYER) |
29 | #define MPA_SYNTH_ON_COP | 29 | #define MPA_SYNTH_ON_COP |
30 | #endif | 30 | #endif |
31 | 31 | ||
@@ -34,8 +34,7 @@ struct mad_frame frame IBSS_ATTR; | |||
34 | struct mad_synth synth IBSS_ATTR; | 34 | struct mad_synth synth IBSS_ATTR; |
35 | 35 | ||
36 | #ifdef MPA_SYNTH_ON_COP | 36 | #ifdef MPA_SYNTH_ON_COP |
37 | volatile short synth_running IBSS_ATTR; /*synthesis is running*/ | 37 | volatile short die IBSS_ATTR = 0; /*thread should die*/ |
38 | volatile short die IBSS_ATTR; /*thread should die*/ | ||
39 | 38 | ||
40 | #if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022) | 39 | #if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022) |
41 | mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR; | 40 | mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR; |
@@ -68,7 +67,6 @@ void init_mad(void) | |||
68 | #ifdef MPA_SYNTH_ON_COP | 67 | #ifdef MPA_SYNTH_ON_COP |
69 | frame.sbsample_prev = &sbsample_prev; | 68 | frame.sbsample_prev = &sbsample_prev; |
70 | ci->memset(&sbsample_prev, 0, sizeof(sbsample_prev)); | 69 | ci->memset(&sbsample_prev, 0, sizeof(sbsample_prev)); |
71 | synth_running=0; | ||
72 | #else | 70 | #else |
73 | frame.sbsample_prev = &sbsample; | 71 | frame.sbsample_prev = &sbsample; |
74 | #endif | 72 | #endif |
@@ -208,73 +206,78 @@ static struct thread_entry *mad_synth_thread_p; | |||
208 | static void mad_synth_thread(void){ | 206 | static void mad_synth_thread(void){ |
209 | 207 | ||
210 | while(1){ | 208 | while(1){ |
209 | ci->semaphore_release(&synth_done_sem); | ||
211 | ci->semaphore_wait(&synth_pending_sem); | 210 | ci->semaphore_wait(&synth_pending_sem); |
212 | 211 | ||
213 | if(die){ | 212 | if(die) |
214 | die=0; | 213 | break; |
215 | invalidate_icache(); | 214 | |
216 | return ; | ||
217 | } | ||
218 | synth_running = 1; | ||
219 | mad_synth_frame(&synth, &frame); | 215 | mad_synth_frame(&synth, &frame); |
220 | synth_running = 0; | ||
221 | ci->semaphore_release(&synth_done_sem); | ||
222 | } | 216 | } |
223 | } | 217 | } |
224 | 218 | ||
225 | 219 | /* wait for the synth thread to go idle which indicates a PCM frame has been | |
226 | static int mad_synth_thread_wait_pcm(void){ | 220 | * synthesized */ |
221 | static inline void mad_synth_thread_wait_pcm(void){ | ||
227 | ci->semaphore_wait(&synth_done_sem); | 222 | ci->semaphore_wait(&synth_done_sem); |
228 | return 0; | ||
229 | } | 223 | } |
230 | 224 | ||
225 | /* increment the done semaphore - used after a wait for idle to preserve the | ||
226 | * semaphore count */ | ||
227 | static inline void mad_synth_thread_unwait_pcm(void){ | ||
228 | ci->semaphore_release(&synth_done_sem); | ||
229 | } | ||
230 | |||
231 | /* after synth thread has gone idle - switch decoded frames and commence | ||
232 | * synthesis on it */ | ||
231 | static void mad_synth_thread_ready(void){ | 233 | static void mad_synth_thread_ready(void){ |
232 | mad_fixed_t (*temp)[2][36][32]; | 234 | mad_fixed_t (*temp)[2][36][32]; |
233 | while(1){ | 235 | |
234 | /*check if synth is currently running before changing its inputs! */ | 236 | /*circular buffer that holds 2 frames' samples*/ |
235 | if(!synth_running){ | 237 | temp=frame.sbsample; |
236 | /*circular buffer that holds 2 frames' samples*/ | 238 | frame.sbsample = frame.sbsample_prev; |
237 | temp=frame.sbsample; | 239 | frame.sbsample_prev=temp; |
238 | frame.sbsample = frame.sbsample_prev; | 240 | |
239 | frame.sbsample_prev=temp; | 241 | ci->semaphore_release(&synth_pending_sem); |
240 | |||
241 | ci->semaphore_release(&synth_pending_sem); | ||
242 | return ; | ||
243 | } | ||
244 | ci->yield(); /*synth thread currently running, wait for it*/ | ||
245 | } | ||
246 | } | 242 | } |
247 | 243 | ||
248 | static int mad_synth_thread_create(void){ | 244 | static bool mad_synth_thread_create(void){ |
249 | synth_running=0; | 245 | ci->semaphore_init(&synth_done_sem, 1, 0); |
250 | die=0; | 246 | ci->semaphore_init(&synth_pending_sem, 1, 0); |
251 | |||
252 | ci->semaphore_init(&synth_done_sem, 1, 0); | ||
253 | ci->semaphore_init(&synth_pending_sem, 1, 0); | ||
254 | 247 | ||
255 | mad_synth_thread_p = ci->create_thread(mad_synth_thread, | 248 | mad_synth_thread_p = ci->create_thread(mad_synth_thread, |
256 | mad_synth_thread_stack, | 249 | mad_synth_thread_stack, |
257 | sizeof(mad_synth_thread_stack), 0, | 250 | sizeof(mad_synth_thread_stack), 0, |
258 | mad_synth_thread_name | 251 | mad_synth_thread_name |
259 | IF_PRIO(, PRIORITY_PLAYBACK), COP); | 252 | IF_PRIO(, PRIORITY_PLAYBACK) |
260 | 253 | IF_COP(, COP)); | |
261 | if (mad_synth_thread_p == NULL) | ||
262 | return false; | ||
263 | |||
264 | return true; | ||
265 | 254 | ||
255 | if (mad_synth_thread_p == NULL) | ||
256 | return false; | ||
257 | |||
258 | return true; | ||
259 | } | ||
260 | |||
261 | static void mad_synth_thread_quit(void){ | ||
262 | /*mop up COP thread*/ | ||
263 | die=1; | ||
264 | ci->semaphore_release(&synth_pending_sem); | ||
265 | ci->thread_wait(mad_synth_thread_p); | ||
266 | invalidate_icache(); | ||
266 | } | 267 | } |
267 | #else | 268 | #else |
268 | static void mad_synth_thread_ready(void){ | 269 | static inline void mad_synth_thread_ready(void){ |
269 | mad_synth_frame(&synth, &frame); | 270 | mad_synth_frame(&synth, &frame); |
270 | } | 271 | } |
271 | static int mad_synth_thread_create(void){ | 272 | static inline bool mad_synth_thread_create(void){ |
272 | return 0; | 273 | return true; |
273 | } | 274 | } |
274 | static int mad_synth_thread_wait_pcm(void){ | 275 | static inline void mad_synth_thread_quit(void){ |
275 | return 0; | 276 | } |
277 | static inline void mad_synth_thread_wait_pcm(void){ | ||
278 | } | ||
279 | static inline void mad_synth_thread_unwait_pcm(void){ | ||
276 | } | 280 | } |
277 | |||
278 | #endif | 281 | #endif |
279 | 282 | ||
280 | /* this is the codec entry point */ | 283 | /* this is the codec entry point */ |
@@ -298,12 +301,13 @@ enum codec_status codec_main(void) | |||
298 | /* Create a decoder instance */ | 301 | /* Create a decoder instance */ |
299 | 302 | ||
300 | ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); | 303 | ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); |
304 | |||
305 | /*does nothing on 1 processor systems except return true*/ | ||
306 | if(!mad_synth_thread_create()) | ||
307 | return CODEC_ERROR; | ||
301 | 308 | ||
302 | next_track: | 309 | next_track: |
303 | 310 | ||
304 | /*does nothing on 1 processor systems*/ | ||
305 | mad_synth_thread_create(); | ||
306 | |||
307 | status = CODEC_OK; | 311 | status = CODEC_OK; |
308 | 312 | ||
309 | /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ | 313 | /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ |
@@ -365,11 +369,10 @@ next_track: | |||
365 | if (ci->seek_time) { | 369 | if (ci->seek_time) { |
366 | int newpos; | 370 | int newpos; |
367 | 371 | ||
368 | #ifdef MPA_SYNTH_ON_COP | 372 | /*make sure the synth thread is idle before seeking - MT only*/ |
369 | /*make sure the synth thread is idle before seeking*/ | 373 | mad_synth_thread_wait_pcm(); |
370 | if(synth_running) | 374 | mad_synth_thread_unwait_pcm(); |
371 | mad_synth_thread_wait_pcm(); | 375 | |
372 | #endif | ||
373 | samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000; | 376 | samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000; |
374 | 377 | ||
375 | if (ci->seek_time-1 == 0) { | 378 | if (ci->seek_time-1 == 0) { |
@@ -426,10 +429,10 @@ next_track: | |||
426 | /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm | 429 | /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm |
427 | data (not the one just decoded above). When we exit the decoding | 430 | data (not the one just decoded above). When we exit the decoding |
428 | loop we will need to process the final frame that was decoded. */ | 431 | loop we will need to process the final frame that was decoded. */ |
432 | mad_synth_thread_wait_pcm(); | ||
433 | |||
429 | if (framelength > 0) { | 434 | if (framelength > 0) { |
430 | 435 | ||
431 | mad_synth_thread_wait_pcm(); | ||
432 | |||
433 | /* In case of a mono file, the second array will be ignored. */ | 436 | /* In case of a mono file, the second array will be ignored. */ |
434 | ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip], | 437 | ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip], |
435 | &synth.pcm.samples[1][samples_to_skip], | 438 | &synth.pcm.samples[1][samples_to_skip], |
@@ -438,9 +441,9 @@ next_track: | |||
438 | /* Only skip samples for the first frame added. */ | 441 | /* Only skip samples for the first frame added. */ |
439 | samples_to_skip = 0; | 442 | samples_to_skip = 0; |
440 | } | 443 | } |
441 | 444 | ||
445 | /* Initiate PCM synthesis on the COP (MT) or perform it here (ST) */ | ||
442 | mad_synth_thread_ready(); | 446 | mad_synth_thread_ready(); |
443 | //mad_synth_frame(&synth, &frame); | ||
444 | 447 | ||
445 | /* Check if sample rate and stereo settings changed in this frame. */ | 448 | /* Check if sample rate and stereo settings changed in this frame. */ |
446 | if (frame.header.samplerate != current_frequency) { | 449 | if (frame.header.samplerate != current_frequency) { |
@@ -474,25 +477,22 @@ next_track: | |||
474 | ci->set_elapsed(samplesdone / (current_frequency / 1000)); | 477 | ci->set_elapsed(samplesdone / (current_frequency / 1000)); |
475 | } | 478 | } |
476 | 479 | ||
480 | /* wait for synth idle - MT only*/ | ||
481 | mad_synth_thread_wait_pcm(); | ||
482 | mad_synth_thread_unwait_pcm(); | ||
483 | |||
477 | /* Finish the remaining decoded frame. | 484 | /* Finish the remaining decoded frame. |
478 | Cut the required samples from the end. */ | 485 | Cut the required samples from the end. */ |
479 | if (framelength > stop_skip){ | 486 | if (framelength > stop_skip){ |
480 | mad_synth_thread_wait_pcm(); | ||
481 | ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1], | 487 | ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1], |
482 | framelength - stop_skip); | 488 | framelength - stop_skip); |
483 | } | 489 | } |
484 | #ifdef MPA_SYNTH_ON_COP | ||
485 | /*mop up COP thread*/ | ||
486 | die=1; | ||
487 | ci->semaphore_release(&synth_pending_sem); | ||
488 | ci->thread_wait(mad_synth_thread_p); | ||
489 | invalidate_icache(); | ||
490 | stream.error = 0; | ||
491 | #endif | ||
492 | |||
493 | 490 | ||
494 | if (ci->request_next_track()) | 491 | if (ci->request_next_track()) |
495 | goto next_track; | 492 | goto next_track; |
496 | 493 | ||
494 | /*mop up COP thread - MT only*/ | ||
495 | mad_synth_thread_quit(); | ||
496 | |||
497 | return status; | 497 | return status; |
498 | } | 498 | } |