diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-29 20:50:58 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-29 20:50:58 +0000 |
commit | 84d6f9e89bf1bae7e3669e487541f91f27a86b0a (patch) | |
tree | 29b26568e10f3bf57ef5f334fdfc96ef43102ab4 | |
parent | cc377d5d18534c57d091e04573956c9b747b4ab6 (diff) | |
download | rockbox-84d6f9e89bf1bae7e3669e487541f91f27a86b0a.tar.gz rockbox-84d6f9e89bf1bae7e3669e487541f91f27a86b0a.zip |
Fixed slow track switching and track pre-buffering. Fixed rockboy
crash while audio is playing. Some buffering adjustments made.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6930 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/playback.c | 29 | ||||
-rw-r--r-- | firmware/export/pcm_playback.h | 2 | ||||
-rw-r--r-- | firmware/pcm_playback.c | 97 |
3 files changed, 97 insertions, 31 deletions
diff --git a/apps/playback.c b/apps/playback.c index e6cc68af6b..dccf632dc9 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include "sound.h" | 61 | #include "sound.h" |
62 | #include "metadata.h" | 62 | #include "metadata.h" |
63 | 63 | ||
64 | static volatile bool codec_loaded; | ||
64 | static volatile bool playing; | 65 | static volatile bool playing; |
65 | static volatile bool paused; | 66 | static volatile bool paused; |
66 | 67 | ||
@@ -213,11 +214,20 @@ bool pcm_is_playing(void) | |||
213 | return false; | 214 | return false; |
214 | } | 215 | } |
215 | 216 | ||
217 | bool pcm_is_crossfade_active(void) | ||
218 | { | ||
219 | return false; | ||
220 | } | ||
221 | |||
216 | bool pcm_is_lowdata(void) | 222 | bool pcm_is_lowdata(void) |
217 | { | 223 | { |
218 | return false; | 224 | return false; |
219 | } | 225 | } |
220 | 226 | ||
227 | void pcm_flush_audio(void) | ||
228 | { | ||
229 | } | ||
230 | |||
221 | bool pcm_crossfade_init(void) | 231 | bool pcm_crossfade_init(void) |
222 | { | 232 | { |
223 | return false; | 233 | return false; |
@@ -487,7 +497,8 @@ bool codec_seek_buffer_callback(off_t newpos) | |||
487 | if (difference >= 0) { | 497 | if (difference >= 0) { |
488 | logf("seek: +%d", difference); | 498 | logf("seek: +%d", difference); |
489 | codec_advance_buffer_callback(difference); | 499 | codec_advance_buffer_callback(difference); |
490 | pcm_play_stop(); | 500 | if (!pcm_is_crossfade_active()) |
501 | pcm_play_stop(); | ||
491 | return true; | 502 | return true; |
492 | } | 503 | } |
493 | 504 | ||
@@ -508,6 +519,7 @@ bool codec_seek_buffer_callback(off_t newpos) | |||
508 | if (buf_ridx < 0) | 519 | if (buf_ridx < 0) |
509 | buf_ridx = codecbuflen + buf_ridx; | 520 | buf_ridx = codecbuflen + buf_ridx; |
510 | ci.curpos -= difference; | 521 | ci.curpos -= difference; |
522 | if (!pcm_is_crossfade_active()) | ||
511 | pcm_play_stop(); | 523 | pcm_play_stop(); |
512 | 524 | ||
513 | return true; | 525 | return true; |
@@ -554,7 +566,7 @@ void yield_codecs(void) | |||
554 | if (!pcm_is_playing()) | 566 | if (!pcm_is_playing()) |
555 | sleep(5); | 567 | sleep(5); |
556 | while (pcm_is_lowdata() && !ci.stop_codec && | 568 | while (pcm_is_lowdata() && !ci.stop_codec && |
557 | playing && queue_empty(&audio_queue)) | 569 | playing && queue_empty(&audio_queue) && codecbufused > (128*1024)) |
558 | yield(); | 570 | yield(); |
559 | } | 571 | } |
560 | 572 | ||
@@ -937,8 +949,7 @@ void audio_check_buffer(void) | |||
937 | 949 | ||
938 | /* Limit buffering size at first run. */ | 950 | /* Limit buffering size at first run. */ |
939 | if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) { | 951 | if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) { |
940 | fill_bytesleft = conf_bufferlimit; | 952 | fill_bytesleft = conf_bufferlimit - codecbufused; |
941 | conf_bufferlimit = 0; | ||
942 | } | 953 | } |
943 | 954 | ||
944 | /* Try to load remainings of the file. */ | 955 | /* Try to load remainings of the file. */ |
@@ -956,6 +967,7 @@ void audio_check_buffer(void) | |||
956 | last_peek_offset++; | 967 | last_peek_offset++; |
957 | } else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) { | 968 | } else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) { |
958 | filling = false; | 969 | filling = false; |
970 | conf_bufferlimit = 0; | ||
959 | pcm_set_boost_mode(false); | 971 | pcm_set_boost_mode(false); |
960 | if (playing) | 972 | if (playing) |
961 | ata_sleep(); | 973 | ata_sleep(); |
@@ -1128,7 +1140,7 @@ void audio_thread(void) | |||
1128 | ci.stop_codec = true; | 1140 | ci.stop_codec = true; |
1129 | ci.reload_codec = false; | 1141 | ci.reload_codec = false; |
1130 | ci.seek_time = 0; | 1142 | ci.seek_time = 0; |
1131 | //pcm_play_stop(); | 1143 | pcm_flush_audio(); |
1132 | audio_play_start((int)ev.data); | 1144 | audio_play_start((int)ev.data); |
1133 | break ; | 1145 | break ; |
1134 | 1146 | ||
@@ -1195,6 +1207,7 @@ void codec_thread(void) | |||
1195 | switch (ev.id) { | 1207 | switch (ev.id) { |
1196 | case CODEC_LOAD_DISK: | 1208 | case CODEC_LOAD_DISK: |
1197 | ci.stop_codec = false; | 1209 | ci.stop_codec = false; |
1210 | codec_loaded = true; | ||
1198 | status = codec_load_file((char *)ev.data); | 1211 | status = codec_load_file((char *)ev.data); |
1199 | break ; | 1212 | break ; |
1200 | 1213 | ||
@@ -1209,6 +1222,7 @@ void codec_thread(void) | |||
1209 | 1222 | ||
1210 | ci.stop_codec = false; | 1223 | ci.stop_codec = false; |
1211 | wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf; | 1224 | wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf; |
1225 | codec_loaded = true; | ||
1212 | status = codec_load_ram(cur_ti->codecbuf, codecsize, | 1226 | status = codec_load_ram(cur_ti->codecbuf, codecsize, |
1213 | &codecbuf[0], wrap); | 1227 | &codecbuf[0], wrap); |
1214 | break ; | 1228 | break ; |
@@ -1220,6 +1234,8 @@ void codec_thread(void) | |||
1220 | break ; | 1234 | break ; |
1221 | #endif | 1235 | #endif |
1222 | } | 1236 | } |
1237 | |||
1238 | codec_loaded = false; | ||
1223 | 1239 | ||
1224 | switch (ev.id) { | 1240 | switch (ev.id) { |
1225 | case CODEC_LOAD_DISK: | 1241 | case CODEC_LOAD_DISK: |
@@ -1297,6 +1313,8 @@ void audio_stop(void) | |||
1297 | { | 1313 | { |
1298 | logf("audio_stop"); | 1314 | logf("audio_stop"); |
1299 | queue_post(&audio_queue, AUDIO_STOP, 0); | 1315 | queue_post(&audio_queue, AUDIO_STOP, 0); |
1316 | while (playing || codec_loaded) | ||
1317 | yield(); | ||
1300 | } | 1318 | } |
1301 | 1319 | ||
1302 | void audio_pause(void) | 1320 | void audio_pause(void) |
@@ -1524,6 +1542,7 @@ void audio_init(void) | |||
1524 | filling = false; | 1542 | filling = false; |
1525 | codecbuf = &audiobuf[MALLOC_BUFSIZE]; | 1543 | codecbuf = &audiobuf[MALLOC_BUFSIZE]; |
1526 | playing = false; | 1544 | playing = false; |
1545 | codec_loaded = false; | ||
1527 | paused = false; | 1546 | paused = false; |
1528 | track_changed = false; | 1547 | track_changed = false; |
1529 | current_fd = -1; | 1548 | current_fd = -1; |
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index 07e33e96bf..554e975354 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h | |||
@@ -35,6 +35,7 @@ void pcm_play_data(const unsigned char* start, int size, | |||
35 | void pcm_play_stop(void); | 35 | void pcm_play_stop(void); |
36 | void pcm_play_pause(bool play); | 36 | void pcm_play_pause(bool play); |
37 | bool pcm_is_playing(void); | 37 | bool pcm_is_playing(void); |
38 | bool pcm_is_crossfade_active(void); | ||
38 | 39 | ||
39 | /* These functions are for playing chained buffers of PCM data */ | 40 | /* These functions are for playing chained buffers of PCM data */ |
40 | void pcm_play_init(void); | 41 | void pcm_play_init(void); |
@@ -45,6 +46,7 @@ void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left)); | |||
45 | 46 | ||
46 | void pcm_set_boost_mode(bool state); | 47 | void pcm_set_boost_mode(bool state); |
47 | bool pcm_is_lowdata(void); | 48 | bool pcm_is_lowdata(void); |
49 | void pcm_flush_buffer(long length); | ||
48 | bool pcm_crossfade_init(void); | 50 | bool pcm_crossfade_init(void); |
49 | void audiobuffer_add_event(void (*event_handler)(void)); | 51 | void audiobuffer_add_event(void (*event_handler)(void)); |
50 | unsigned int audiobuffer_get_latency(void); | 52 | unsigned int audiobuffer_get_latency(void); |
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index b0bdfbbb32..03cc106016 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -47,7 +47,7 @@ | |||
47 | /* Must be a power of 2 */ | 47 | /* Must be a power of 2 */ |
48 | #define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE) | 48 | #define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE) |
49 | #define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1) | 49 | #define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1) |
50 | #define PCM_WATERMARK (CHUNK_SIZE * 4) | 50 | #define PCM_WATERMARK (CHUNK_SIZE * 6) |
51 | #define PCM_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8) | 51 | #define PCM_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8) |
52 | 52 | ||
53 | static bool pcm_playing; | 53 | static bool pcm_playing; |
@@ -60,6 +60,16 @@ long audiobuffer_free; | |||
60 | static long audiobuffer_fillpos; | 60 | static long audiobuffer_fillpos; |
61 | static bool boost_mode; | 61 | static bool boost_mode; |
62 | 62 | ||
63 | /* Crossfade modes. If CFM_CROSSFADE is selected, normal | ||
64 | * crossfader will activate. Selecting CFM_FLUSH is a special | ||
65 | * operation that only overwrites the pcm buffer without crossfading. | ||
66 | */ | ||
67 | enum { | ||
68 | CFM_CROSSFADE, | ||
69 | CFM_FLUSH | ||
70 | }; | ||
71 | |||
72 | static int crossfade_mode; | ||
63 | static bool crossfade_enabled; | 73 | static bool crossfade_enabled; |
64 | static bool crossfade_active; | 74 | static bool crossfade_active; |
65 | static bool crossfade_init; | 75 | static bool crossfade_init; |
@@ -346,8 +356,6 @@ bool pcm_play_add_chunk(void *addr, int size, void (*callback)(void)) | |||
346 | 356 | ||
347 | void pcm_watermark_callback(int bytes_left) | 357 | void pcm_watermark_callback(int bytes_left) |
348 | { | 358 | { |
349 | (void)bytes_left; | ||
350 | |||
351 | /* Fill audio buffer by boosting cpu */ | 359 | /* Fill audio buffer by boosting cpu */ |
352 | pcm_boost(true); | 360 | pcm_boost(true); |
353 | if (bytes_left <= CHUNK_SIZE * 2) | 361 | if (bytes_left <= CHUNK_SIZE * 2) |
@@ -395,12 +403,25 @@ bool pcm_crossfade_init(void) | |||
395 | return false; | 403 | return false; |
396 | } | 404 | } |
397 | logf("crossfading!"); | 405 | logf("crossfading!"); |
406 | crossfade_mode = CFM_CROSSFADE; | ||
398 | crossfade_init = true; | 407 | crossfade_init = true; |
399 | 408 | ||
400 | return true; | 409 | return true; |
401 | 410 | ||
402 | } | 411 | } |
403 | 412 | ||
413 | /** Initialize a track switch so that audio playback will not stop but | ||
414 | * the switch to next track would happen as soon as possible. | ||
415 | */ | ||
416 | void pcm_flush_audio(void) | ||
417 | { | ||
418 | if (crossfade_init || crossfade_active) | ||
419 | return ; | ||
420 | |||
421 | crossfade_mode = CFM_FLUSH; | ||
422 | crossfade_init = true; | ||
423 | } | ||
424 | |||
404 | void pcm_flush_fillpos(void) | 425 | void pcm_flush_fillpos(void) |
405 | { | 426 | { |
406 | if (audiobuffer_fillpos) { | 427 | if (audiobuffer_fillpos) { |
@@ -419,19 +440,29 @@ void pcm_flush_fillpos(void) | |||
419 | 440 | ||
420 | static void crossfade_start(void) | 441 | static void crossfade_start(void) |
421 | { | 442 | { |
422 | if (!crossfade_init) | ||
423 | return ; | ||
424 | |||
425 | crossfade_init = 0; | 443 | crossfade_init = 0; |
426 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6) | 444 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 4) { |
445 | if (crossfade_mode == CFM_FLUSH) | ||
446 | pcm_play_stop(); | ||
427 | return ; | 447 | return ; |
428 | 448 | } | |
449 | |||
429 | pcm_flush_fillpos(); | 450 | pcm_flush_fillpos(); |
430 | pcm_boost(true); | 451 | pcm_boost(true); |
431 | crossfade_active = true; | 452 | crossfade_active = true; |
432 | crossfade_pos = audiobuffer_pos; | 453 | crossfade_pos = audiobuffer_pos; |
433 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; | 454 | |
434 | crossfade_rem = crossfade_amount; | 455 | switch (crossfade_mode) { |
456 | case CFM_CROSSFADE: | ||
457 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; | ||
458 | crossfade_rem = crossfade_amount; | ||
459 | break ; | ||
460 | |||
461 | case CFM_FLUSH: | ||
462 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; | ||
463 | crossfade_rem = crossfade_amount; | ||
464 | break ; | ||
465 | } | ||
435 | 466 | ||
436 | crossfade_pos -= crossfade_amount*2; | 467 | crossfade_pos -= crossfade_amount*2; |
437 | if (crossfade_pos < 0) | 468 | if (crossfade_pos < 0) |
@@ -441,25 +472,40 @@ static void crossfade_start(void) | |||
441 | static __inline | 472 | static __inline |
442 | int crossfade(short *buf, const short *buf2, int length) | 473 | int crossfade(short *buf, const short *buf2, int length) |
443 | { | 474 | { |
444 | int i, size; | 475 | int size, i; |
445 | int val1 = (crossfade_rem<<10)/crossfade_amount; | 476 | int val1, val2; |
446 | int val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount; | ||
447 | 477 | ||
448 | // logf("cfi: %d/%d", length, crossfade_rem); | ||
449 | size = MIN(length, crossfade_rem); | 478 | size = MIN(length, crossfade_rem); |
450 | for (i = 0; i < size; i++) { | 479 | switch (crossfade_mode) { |
451 | buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10; | 480 | case CFM_CROSSFADE: |
481 | val1 = (crossfade_rem<<10)/crossfade_amount; | ||
482 | val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount; | ||
483 | |||
484 | for (i = 0; i < size; i++) { | ||
485 | buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10; | ||
486 | } | ||
487 | break ; | ||
488 | |||
489 | case CFM_FLUSH: | ||
490 | for (i = 0; i < size; i++) { | ||
491 | buf[i] = buf2[i]; | ||
492 | } | ||
493 | //memcpy((char *)buf, (char *)buf2, size*2); | ||
494 | break ; | ||
452 | } | 495 | } |
453 | crossfade_rem -= i; | 496 | |
497 | crossfade_rem -= size; | ||
454 | if (crossfade_rem <= 0) | 498 | if (crossfade_rem <= 0) |
455 | crossfade_active = false; | 499 | crossfade_active = false; |
456 | 500 | ||
457 | return size; | 501 | return size; |
458 | } | 502 | } |
459 | 503 | ||
460 | inline static bool prepare_insert(long length) | 504 | inline static bool prepare_insert(long length) |
461 | { | 505 | { |
462 | crossfade_start(); | 506 | if (crossfade_init) |
507 | crossfade_start(); | ||
508 | |||
463 | if (audiobuffer_free < length + audiobuffer_fillpos | 509 | if (audiobuffer_free < length + audiobuffer_fillpos |
464 | + CHUNK_SIZE && !crossfade_active) { | 510 | + CHUNK_SIZE && !crossfade_active) { |
465 | pcm_boost(false); | 511 | pcm_boost(false); |
@@ -487,15 +533,12 @@ void* pcm_request_buffer(long length, long *realsize) | |||
487 | 533 | ||
488 | if (crossfade_active) { | 534 | if (crossfade_active) { |
489 | *realsize = MIN(length, PCMBUF_GUARD); | 535 | *realsize = MIN(length, PCMBUF_GUARD); |
490 | //logf("cfb:%d/%d", *realsize, length); | ||
491 | ptr = &guardbuf[0]; | 536 | ptr = &guardbuf[0]; |
492 | } else { | 537 | } else { |
493 | *realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos | 538 | *realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos |
494 | - audiobuffer_fillpos); | 539 | - audiobuffer_fillpos); |
495 | if (*realsize < length) { | 540 | if (*realsize < length) { |
496 | //logf("gbr1:%d/%d", *realsize, length); | ||
497 | *realsize += MIN((long)(length - *realsize), PCMBUF_GUARD); | 541 | *realsize += MIN((long)(length - *realsize), PCMBUF_GUARD); |
498 | //logf("gbr2:%d/%d", *realsize, length); | ||
499 | } | 542 | } |
500 | ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos]; | 543 | ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos]; |
501 | } | 544 | } |
@@ -503,17 +546,20 @@ void* pcm_request_buffer(long length, long *realsize) | |||
503 | return ptr; | 546 | return ptr; |
504 | } | 547 | } |
505 | 548 | ||
549 | bool pcm_is_crossfade_active(void) | ||
550 | { | ||
551 | return crossfade_active; | ||
552 | } | ||
553 | |||
506 | void pcm_flush_buffer(long length) | 554 | void pcm_flush_buffer(long length) |
507 | { | 555 | { |
508 | int copy_n; | 556 | int copy_n; |
509 | char *buf; | 557 | char *buf; |
510 | 558 | ||
511 | if (crossfade_active) { | 559 | if (crossfade_active) { |
512 | //logf("cfbf"); | ||
513 | buf = &guardbuf[0]; | 560 | buf = &guardbuf[0]; |
514 | length = MIN(length, PCMBUF_GUARD); | 561 | length = MIN(length, PCMBUF_GUARD); |
515 | while (length > 0 && crossfade_active) { | 562 | while (length > 0 && crossfade_active) { |
516 | //logf("cfl:%d", length); | ||
517 | copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos); | 563 | copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos); |
518 | copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos], | 564 | copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos], |
519 | (const short *)buf, copy_n/2); | 565 | (const short *)buf, copy_n/2); |
@@ -525,7 +571,6 @@ void pcm_flush_buffer(long length) | |||
525 | } | 571 | } |
526 | 572 | ||
527 | while (length > 0) { | 573 | while (length > 0) { |
528 | //logf("cfl2:%d", length); | ||
529 | copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos); | 574 | copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos); |
530 | memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n); | 575 | memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n); |
531 | audiobuffer_fillpos = copy_n; | 576 | audiobuffer_fillpos = copy_n; |
@@ -545,7 +590,6 @@ void pcm_flush_buffer(long length) | |||
545 | 590 | ||
546 | copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos); | 591 | copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos); |
547 | if (copy_n > 0) { | 592 | if (copy_n > 0) { |
548 | //logf("gbu:%d/%d/%d", copy_n, audiobuffer_fillpos, audiobuffer_pos); | ||
549 | audiobuffer_fillpos -= copy_n; | 593 | audiobuffer_fillpos -= copy_n; |
550 | pcm_flush_fillpos(); | 594 | pcm_flush_fillpos(); |
551 | copy_n = MIN(copy_n, PCMBUF_GUARD); | 595 | copy_n = MIN(copy_n, PCMBUF_GUARD); |
@@ -652,6 +696,7 @@ void pcm_play_start(void) | |||
652 | pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback); | 696 | pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback); |
653 | } | 697 | } |
654 | crossfade_active = false; | 698 | crossfade_active = false; |
699 | |||
655 | if(!pcm_is_playing()) | 700 | if(!pcm_is_playing()) |
656 | { | 701 | { |
657 | size = MIN(desc->size, 32768); | 702 | size = MIN(desc->size, 32768); |