diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2005-07-07 07:15:05 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2005-07-07 07:15:05 +0000 |
commit | 3eb962d13bd4ca8c29ab33c41428a44e644e59ec (patch) | |
tree | 6ad56c24745868d9c56a56dc1278cfde4f5573ff /firmware/pcm_playback.c | |
parent | 8d3855eb536d4b8f1459c9b2da3beb5a0ac328b4 (diff) | |
download | rockbox-3eb962d13bd4ca8c29ab33c41428a44e644e59ec.tar.gz rockbox-3eb962d13bd4ca8c29ab33c41428a44e644e59ec.zip |
PCM buffering fixes. Made a temporary workaround for playback glitch
bug (see the patch).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7049 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r-- | firmware/pcm_playback.c | 87 |
1 files changed, 48 insertions, 39 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index be7f4e4379..6b9a4bbd5c 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -146,7 +146,7 @@ static void dma_stop(void) | |||
146 | /* Reset the FIFO */ | 146 | /* Reset the FIFO */ |
147 | IIS2CONFIG = 0x800; | 147 | IIS2CONFIG = 0x800; |
148 | EBU1CONFIG = 0x800; | 148 | EBU1CONFIG = 0x800; |
149 | 149 | ||
150 | pcmbuf_unplayed_bytes = 0; | 150 | pcmbuf_unplayed_bytes = 0; |
151 | last_chunksize = 0; | 151 | last_chunksize = 0; |
152 | audiobuffer_pos = 0; | 152 | audiobuffer_pos = 0; |
@@ -213,7 +213,8 @@ static void pcm_play_callback(unsigned char** start, long* size) | |||
213 | if(pcm_play_num_used_buffers()) | 213 | if(pcm_play_num_used_buffers()) |
214 | { | 214 | { |
215 | /* Play max 64K at a time */ | 215 | /* Play max 64K at a time */ |
216 | sz = MIN(desc->size, 32768); | 216 | //sz = MIN(desc->size, 32768); |
217 | sz = desc->size; | ||
217 | *start = desc->addr; | 218 | *start = desc->addr; |
218 | *size = sz; | 219 | *size = sz; |
219 | 220 | ||
@@ -245,11 +246,21 @@ void pcm_play_data(const unsigned char* start, int size, | |||
245 | void (*get_more)(unsigned char** start, long* size)) | 246 | void (*get_more)(unsigned char** start, long* size)) |
246 | { | 247 | { |
247 | callback_for_more = get_more; | 248 | callback_for_more = get_more; |
249 | /** FIXME: This is a temporary fix to prevent playback glitches when | ||
250 | * playing the first file. We will just drop the first frame to prevent | ||
251 | * that problem from occurring. | ||
252 | * Some debug data: | ||
253 | * - This problem will occur only when the first file. | ||
254 | * - First frame will be totally corrupt and the song will begin | ||
255 | * from the next frame. But at the next time (when the bug has | ||
256 | * already happened), the song will start from first frame. | ||
257 | * - Dropping some frames directly from (mpa) codec will also | ||
258 | * prevent the problem from happening. So it's unlikely you can | ||
259 | * find the explanation for this bug from this file. | ||
260 | */ | ||
261 | get_more((unsigned char **)&start, (long *)&size); // REMOVE THIS TO TEST | ||
248 | get_more(&next_start, &next_size); | 262 | get_more(&next_start, &next_size); |
249 | dma_start(start, size); | 263 | dma_start(start, size); |
250 | |||
251 | /* Sleep a while, then unmute audio output */ | ||
252 | sleep(HZ/8); | ||
253 | uda1380_mute(false); | 264 | uda1380_mute(false); |
254 | } | 265 | } |
255 | 266 | ||
@@ -310,7 +321,7 @@ void DMA0(void) | |||
310 | if(res & 0x70) | 321 | if(res & 0x70) |
311 | { | 322 | { |
312 | dma_stop(); | 323 | dma_stop(); |
313 | logf("DMA Error"); | 324 | logf("DMA Error:0x%04x", res); |
314 | } | 325 | } |
315 | else | 326 | else |
316 | { | 327 | { |
@@ -326,7 +337,7 @@ void DMA0(void) | |||
326 | { | 337 | { |
327 | /* Finished playing */ | 338 | /* Finished playing */ |
328 | dma_stop(); | 339 | dma_stop(); |
329 | logf("DMA No Data"); | 340 | logf("DMA No Data:0x%04x", res); |
330 | } | 341 | } |
331 | } | 342 | } |
332 | 343 | ||
@@ -431,7 +442,7 @@ bool pcm_is_lowdata(void) | |||
431 | bool pcm_crossfade_init(void) | 442 | bool pcm_crossfade_init(void) |
432 | { | 443 | { |
433 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled | 444 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled |
434 | || crossfade_active) { | 445 | || crossfade_active || crossfade_init) { |
435 | return false; | 446 | return false; |
436 | } | 447 | } |
437 | logf("pcm_crossfade_init"); | 448 | logf("pcm_crossfade_init"); |
@@ -457,21 +468,27 @@ void pcm_flush_audio(void) | |||
457 | 468 | ||
458 | void pcm_flush_fillpos(void) | 469 | void pcm_flush_fillpos(void) |
459 | { | 470 | { |
460 | if (audiobuffer_fillpos) { | 471 | int copy_n; |
461 | while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], | 472 | |
462 | audiobuffer_fillpos, pcm_event_handler)) { | 473 | copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE); |
474 | |||
475 | if (copy_n) { | ||
476 | while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], | ||
477 | copy_n, pcm_event_handler)) { | ||
463 | pcm_boost(false); | 478 | pcm_boost(false); |
464 | yield(); | 479 | yield(); |
465 | /* This is a fatal error situation that should never happen. */ | 480 | /* This is a fatal error situation that should never happen. */ |
466 | if (!pcm_playing) | 481 | if (!pcm_playing) { |
482 | logf("pcm_flush_fillpos error"); | ||
467 | break ; | 483 | break ; |
484 | } | ||
468 | } | 485 | } |
469 | pcm_event_handler = NULL; | 486 | pcm_event_handler = NULL; |
470 | audiobuffer_pos += audiobuffer_fillpos; | 487 | audiobuffer_pos += copy_n; |
471 | if (audiobuffer_pos >= PCMBUF_SIZE) | 488 | if (audiobuffer_pos >= PCMBUF_SIZE) |
472 | audiobuffer_pos -= PCMBUF_SIZE; | 489 | audiobuffer_pos -= PCMBUF_SIZE; |
473 | audiobuffer_free -= audiobuffer_fillpos; | 490 | audiobuffer_free -= copy_n; |
474 | audiobuffer_fillpos = 0; | 491 | audiobuffer_fillpos -= copy_n; |
475 | } | 492 | } |
476 | } | 493 | } |
477 | 494 | ||
@@ -541,7 +558,7 @@ int crossfade(short *buf, const short *buf2, int length) | |||
541 | return size; | 558 | return size; |
542 | } | 559 | } |
543 | 560 | ||
544 | inline static bool prepare_insert(long length) | 561 | static bool prepare_insert(long length) |
545 | { | 562 | { |
546 | if (crossfade_init) | 563 | if (crossfade_init) |
547 | crossfade_start(); | 564 | crossfade_start(); |
@@ -566,9 +583,10 @@ void* pcm_request_buffer(long length, long *realsize) | |||
566 | { | 583 | { |
567 | void *ptr = NULL; | 584 | void *ptr = NULL; |
568 | 585 | ||
569 | if (!prepare_insert(length)) { | 586 | while (audiobuffer_free < length + audiobuffer_fillpos |
570 | *realsize = 0; | 587 | + CHUNK_SIZE && !crossfade_active) { |
571 | return NULL; | 588 | pcm_boost(false); |
589 | yield(); | ||
572 | } | 590 | } |
573 | 591 | ||
574 | if (crossfade_active) { | 592 | if (crossfade_active) { |
@@ -595,6 +613,8 @@ void pcm_flush_buffer(long length) | |||
595 | { | 613 | { |
596 | int copy_n; | 614 | int copy_n; |
597 | char *buf; | 615 | char *buf; |
616 | |||
617 | prepare_insert(length); | ||
598 | 618 | ||
599 | if (crossfade_active) { | 619 | if (crossfade_active) { |
600 | buf = &guardbuf[0]; | 620 | buf = &guardbuf[0]; |
@@ -620,14 +640,14 @@ void pcm_flush_buffer(long length) | |||
620 | pcm_flush_fillpos(); | 640 | pcm_flush_fillpos(); |
621 | } | 641 | } |
622 | } | 642 | } |
623 | 643 | ||
624 | audiobuffer_fillpos += length; | 644 | audiobuffer_fillpos += length; |
625 | 645 | ||
626 | try_flush: | 646 | try_flush: |
627 | if (audiobuffer_fillpos < CHUNK_SIZE && PCMBUF_SIZE | 647 | if (audiobuffer_fillpos < CHUNK_SIZE && PCMBUF_SIZE |
628 | - audiobuffer_pos - audiobuffer_fillpos > 0) | 648 | - audiobuffer_pos - audiobuffer_fillpos > 0) |
629 | return ; | 649 | return ; |
630 | 650 | ||
631 | copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos); | 651 | copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos); |
632 | if (copy_n > 0) { | 652 | if (copy_n > 0) { |
633 | audiobuffer_fillpos -= copy_n; | 653 | audiobuffer_fillpos -= copy_n; |
@@ -699,15 +719,9 @@ void pcm_play_init(void) | |||
699 | audiobuffer = &audiobuf[(audiobufend - audiobuf) - | 719 | audiobuffer = &audiobuf[(audiobufend - audiobuf) - |
700 | PCMBUF_SIZE - PCMBUF_GUARD]; | 720 | PCMBUF_SIZE - PCMBUF_GUARD]; |
701 | guardbuf = &audiobuffer[PCMBUF_SIZE]; | 721 | guardbuf = &audiobuffer[PCMBUF_SIZE]; |
702 | audiobuffer_free = PCMBUF_SIZE; | 722 | |
703 | audiobuffer_pos = 0; | 723 | /* Call dma_stop to initialize everything. */ |
704 | audiobuffer_fillpos = 0; | 724 | dma_stop(); |
705 | boost_mode = 0; | ||
706 | pcmbuf_read_index = 0; | ||
707 | pcmbuf_write_index = 0; | ||
708 | pcmbuf_unplayed_bytes = 0; | ||
709 | crossfade_active = false; | ||
710 | crossfade_init = false; | ||
711 | pcm_event_handler = NULL; | 725 | pcm_event_handler = NULL; |
712 | } | 726 | } |
713 | 727 | ||
@@ -723,9 +737,8 @@ bool pcm_is_crossfade_enabled(void) | |||
723 | 737 | ||
724 | void pcm_play_start(void) | 738 | void pcm_play_start(void) |
725 | { | 739 | { |
726 | struct pcmbufdesc *desc = &pcmbuffers[pcmbuf_read_index]; | 740 | unsigned long size; |
727 | int size; | 741 | unsigned char *start; |
728 | char *start; | ||
729 | 742 | ||
730 | if (crossfade_enabled) { | 743 | if (crossfade_enabled) { |
731 | pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback); | 744 | pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback); |
@@ -736,11 +749,7 @@ void pcm_play_start(void) | |||
736 | 749 | ||
737 | if(!pcm_is_playing()) | 750 | if(!pcm_is_playing()) |
738 | { | 751 | { |
739 | size = MIN(desc->size, 32768); | 752 | pcm_play_callback(&start, &size); |
740 | start = desc->addr; | ||
741 | last_chunksize = size; | ||
742 | desc->size -= size; | ||
743 | desc->addr += size; | ||
744 | pcm_play_data(start, size, pcm_play_callback); | 753 | pcm_play_data(start, size, pcm_play_callback); |
745 | } | 754 | } |
746 | } | 755 | } |