summaryrefslogtreecommitdiff
path: root/firmware/pcm_playback.c
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-06-29 20:50:58 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-06-29 20:50:58 +0000
commit84d6f9e89bf1bae7e3669e487541f91f27a86b0a (patch)
tree29b26568e10f3bf57ef5f334fdfc96ef43102ab4 /firmware/pcm_playback.c
parentcc377d5d18534c57d091e04573956c9b747b4ab6 (diff)
downloadrockbox-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
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r--firmware/pcm_playback.c97
1 files changed, 71 insertions, 26 deletions
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
53static bool pcm_playing; 53static bool pcm_playing;
@@ -60,6 +60,16 @@ long audiobuffer_free;
60static long audiobuffer_fillpos; 60static long audiobuffer_fillpos;
61static bool boost_mode; 61static 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 */
67enum {
68 CFM_CROSSFADE,
69 CFM_FLUSH
70};
71
72static int crossfade_mode;
63static bool crossfade_enabled; 73static bool crossfade_enabled;
64static bool crossfade_active; 74static bool crossfade_active;
65static bool crossfade_init; 75static bool crossfade_init;
@@ -346,8 +356,6 @@ bool pcm_play_add_chunk(void *addr, int size, void (*callback)(void))
346 356
347void pcm_watermark_callback(int bytes_left) 357void 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 */
416void 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
404void pcm_flush_fillpos(void) 425void 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
420static void crossfade_start(void) 441static 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)
441static __inline 472static __inline
442int crossfade(short *buf, const short *buf2, int length) 473int 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
460inline static bool prepare_insert(long length) 504inline 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
549bool pcm_is_crossfade_active(void)
550{
551 return crossfade_active;
552}
553
506void pcm_flush_buffer(long length) 554void 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);