summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-07-07 07:15:05 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-07-07 07:15:05 +0000
commit3eb962d13bd4ca8c29ab33c41428a44e644e59ec (patch)
tree6ad56c24745868d9c56a56dc1278cfde4f5573ff
parent8d3855eb536d4b8f1459c9b2da3beb5a0ac328b4 (diff)
downloadrockbox-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
-rw-r--r--apps/codecs.c3
-rw-r--r--apps/codecs/mpa.c20
-rw-r--r--apps/playback.c49
-rw-r--r--firmware/pcm_playback.c87
4 files changed, 87 insertions, 72 deletions
diff --git a/apps/codecs.c b/apps/codecs.c
index d3a9d9e9c1..400e7fbfcf 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -277,6 +277,9 @@ int codec_load_file(const char *plugin)
277 int fd; 277 int fd;
278 int rc; 278 int rc;
279 279
280 /* zero out codec buffer to ensure a properly zeroed bss area */
281 memset(codecbuf, 0, CODEC_SIZE);
282
280 fd = open(plugin, O_RDONLY); 283 fd = open(plugin, O_RDONLY);
281 if (fd < 0) { 284 if (fd < 0) {
282 snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin); 285 snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin);
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 5cf4eb8730..5d6f7d29ad 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -39,12 +39,6 @@ void abort(void) {
39 39
40 40
41#define INPUT_CHUNK_SIZE 8192 41#define INPUT_CHUNK_SIZE 8192
42#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
43
44unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
45unsigned char *OutputPtr;
46unsigned char *GuardPtr = NULL;
47const unsigned char *OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE;
48 42
49mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR; 43mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
50unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR; 44unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
@@ -115,7 +109,6 @@ enum codec_status codec_start(struct codec_api* api)
115 109
116 first_frame = false; 110 first_frame = false;
117 file_end = 0; 111 file_end = 0;
118 OutputPtr = OutputBuffer;
119 112
120 while (!*ci->taginfo_ready) 113 while (!*ci->taginfo_ready)
121 ci->yield(); 114 ci->yield();
@@ -195,7 +188,7 @@ enum codec_status codec_start(struct codec_api* api)
195 } 188 }
196 else if(MAD_RECOVERABLE(Stream.error)) 189 else if(MAD_RECOVERABLE(Stream.error))
197 { 190 {
198 if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr) 191 if(Stream.error!=MAD_ERROR_LOSTSYNC)
199 { 192 {
200 // rb->splash(HZ*1, true, "Recoverable...!"); 193 // rb->splash(HZ*1, true, "Recoverable...!");
201 } 194 }
@@ -209,9 +202,9 @@ enum codec_status codec_start(struct codec_api* api)
209 Status=1; 202 Status=1;
210 break; 203 break;
211 } 204 }
205 break ;
212 } 206 }
213 if (Stream.next_frame) 207
214 ci->advance_buffer_loc((void *)Stream.next_frame);
215 file_end = false; 208 file_end = false;
216 /* ?? Do we need the timer module? */ 209 /* ?? Do we need the timer module? */
217 // mad_timer_add(&Timer,Frame.header.duration); 210 // mad_timer_add(&Timer,Frame.header.duration);
@@ -222,7 +215,7 @@ enum codec_status codec_start(struct codec_api* api)
222 /* We skip start_skip number of samples here, this should only happen for 215 /* We skip start_skip number of samples here, this should only happen for
223 very first frame in the stream. */ 216 very first frame in the stream. */
224 /* TODO: possible for start_skip to exceed one frames worth of samples? */ 217 /* TODO: possible for start_skip to exceed one frames worth of samples? */
225 218
226 if (MAD_NCHANNELS(&Frame.header) == 2) { 219 if (MAD_NCHANNELS(&Frame.header) == 2) {
227 if (current_stereo_mode != STEREO_NONINTERLEAVED) { 220 if (current_stereo_mode != STEREO_NONINTERLEAVED) {
228 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); 221 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
@@ -241,6 +234,11 @@ enum codec_status codec_start(struct codec_api* api)
241 } 234 }
242 start_skip = 0; /* not very elegant, and might want to keep this value */ 235 start_skip = 0; /* not very elegant, and might want to keep this value */
243 236
237 if (Stream.next_frame)
238 ci->advance_buffer_loc((void *)Stream.next_frame);
239 else
240 ci->advance_buffer(size);
241
244 samplesdone += Synth.pcm.length; 242 samplesdone += Synth.pcm.length;
245 samplecount -= Synth.pcm.length; 243 samplecount -= Synth.pcm.length;
246 ci->set_elapsed(samplesdone / (frequency_divider / 10)); 244 ci->set_elapsed(samplesdone / (frequency_divider / 10));
diff --git a/apps/playback.c b/apps/playback.c
index 13c66a43b5..f9caff1c4f 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -659,12 +659,12 @@ void audio_fill_file_buffer(void)
659 buf_widx -= codecbuflen; 659 buf_widx -= codecbuflen;
660 i += rc; 660 i += rc;
661 tracks[track_widx].available += rc; 661 tracks[track_widx].available += rc;
662 tracks[track_widx].filerem -= rc;
663 tracks[track_widx].filepos += rc;
662 codecbufused += rc; 664 codecbufused += rc;
663 fill_bytesleft -= rc; 665 fill_bytesleft -= rc;
664 } 666 }
665 667
666 tracks[track_widx].filerem -= i;
667 tracks[track_widx].filepos += i;
668 /*logf("Filled:%d/%d", tracks[track_widx].available, 668 /*logf("Filled:%d/%d", tracks[track_widx].available,
669 tracks[track_widx].filerem);*/ 669 tracks[track_widx].filerem);*/
670} 670}
@@ -890,26 +890,29 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
890 890
891 /* Starting playback from an offset is only support in MPA at the moment */ 891 /* Starting playback from an offset is only support in MPA at the moment */
892 if (offset > 0) { 892 if (offset > 0) {
893 if ((tracks[track_widx].id3.codectype==AFMT_MPA_L2) || 893 switch (tracks[track_widx].id3.codectype) {
894 (tracks[track_widx].id3.codectype==AFMT_MPA_L3)) { 894 case AFMT_MPA_L2:
895 lseek(fd, offset, SEEK_SET); 895 case AFMT_MPA_L3:
896 tracks[track_widx].id3.offset = offset; 896 lseek(fd, offset, SEEK_SET);
897 mp3_set_elapsed(&tracks[track_widx].id3); 897 tracks[track_widx].id3.offset = offset;
898 tracks[track_widx].filepos = offset; 898 mp3_set_elapsed(&tracks[track_widx].id3);
899 tracks[track_widx].filerem = tracks[track_widx].filesize - offset; 899 tracks[track_widx].filepos = offset;
900 ci.curpos = offset; 900 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
901 tracks[track_widx].start_pos = offset; 901 ci.curpos = offset;
902 } 902 tracks[track_widx].start_pos = offset;
903 else if (tracks[track_widx].id3.codectype==AFMT_WAVPACK) { 903 break;
904 lseek(fd, offset, SEEK_SET); 904
905 tracks[track_widx].id3.offset = offset; 905 case AFMT_WAVPACK:
906 tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2; 906 lseek(fd, offset, SEEK_SET);
907 tracks[track_widx].filepos = offset; 907 tracks[track_widx].id3.offset = offset;
908 tracks[track_widx].filerem = tracks[track_widx].filesize - offset; 908 tracks[track_widx].id3.elapsed = tracks[track_widx].id3.length / 2;
909 ci.curpos = offset; 909 tracks[track_widx].filepos = offset;
910 tracks[track_widx].start_pos = offset; 910 tracks[track_widx].filerem = tracks[track_widx].filesize - offset;
911 } 911 ci.curpos = offset;
912 } 912 tracks[track_widx].start_pos = offset;
913 break;
914 }
915 }
913 916
914 if (start_play) { 917 if (start_play) {
915 track_count++; 918 track_count++;
@@ -1795,6 +1798,8 @@ void audio_init(void)
1795 track_buffer_callback = NULL; 1798 track_buffer_callback = NULL;
1796 track_unbuffer_callback = NULL; 1799 track_unbuffer_callback = NULL;
1797 track_changed_callback = NULL; 1800 track_changed_callback = NULL;
1801 /* Just to prevent cur_ti never be anything random. */
1802 cur_ti = &tracks[0];
1798 1803
1799 logf("abuf:%0x", PCMBUF_SIZE); 1804 logf("abuf:%0x", PCMBUF_SIZE);
1800 logf("fbuf:%0x", codecbuflen); 1805 logf("fbuf:%0x", codecbuflen);
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)
431bool pcm_crossfade_init(void) 442bool 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
458void pcm_flush_fillpos(void) 469void 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
544inline static bool prepare_insert(long length) 561static 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
724void pcm_play_start(void) 738void 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}