summaryrefslogtreecommitdiff
path: root/apps/pcmbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r--apps/pcmbuf.c193
1 files changed, 84 insertions, 109 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 75d8152f7e..580dc315a7 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -454,10 +454,6 @@ size_t pcmbuf_init(unsigned char *bufend)
454 454
455 init_pcmbuffers(); 455 init_pcmbuffers();
456 456
457 if(track_transition){logf("pcmbuf: (init) track transition false");}
458 end_of_track = false;
459 track_transition = false;
460
461#ifdef HAVE_CROSSFADE 457#ifdef HAVE_CROSSFADE
462 pcmbuf_finish_crossfade_enable(); 458 pcmbuf_finish_crossfade_enable();
463#else 459#else
@@ -472,112 +468,84 @@ size_t pcmbuf_init(unsigned char *bufend)
472 468
473/* Track change */ 469/* Track change */
474 470
475/* The codec is moving on to the next track, but the current track is 471void pcmbuf_start_track_change(bool auto_skip)
476 * still playing. Set flags to make sure the elapsed time of the current
477 * track is updated properly, and mark the currently written chunk as the
478 * last one in the track. */
479static void start_gapless_track_change(void)
480{ 472{
481 logf(" gapless track change"); 473 bool crossfade = false;
482 /* we're starting a track transition */
483 track_transition = true;
484
485 /* mark the last chunk in the track */
486 end_of_track = true;
487}
488
489#ifdef HAVE_CROSSFADE 474#ifdef HAVE_CROSSFADE
490static bool pcmbuf_is_crossfade_enabled(void) 475 /* Determine whether this track change needs to crossfade */
491{ 476
492 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE) 477 if(crossfade_enabled && !pcmbuf_is_crossfade_active())
493 return global_settings.playlist_shuffle; 478 {
494 479 switch(global_settings.crossfade)
495 return crossfade_enabled; 480 {
496} 481 case CROSSFADE_ENABLE_AUTOSKIP:
482 crossfade = auto_skip;
483 break;
484 case CROSSFADE_ENABLE_MANSKIP:
485 crossfade = !auto_skip;
486 break;
487 case CROSSFADE_ENABLE_SHUFFLE:
488 crossfade = global_settings.playlist_shuffle;
489 break;
490 case CROSSFADE_ENABLE_SHUFFLE_AND_MANSKIP:
491 crossfade = global_settings.playlist_shuffle && !auto_skip;
492 break;
493 case CROSSFADE_ENABLE_ALWAYS:
494 crossfade = true;
495 break;
496 }
497 }
497#endif 498#endif
499
500 if (!auto_skip || crossfade)
501 /* manual skip or crossfade */
502 {
503 if (crossfade)
504 { logf(" crossfade track change"); }
505 else
506 { logf(" manual track change"); }
507
508 /* Notify the wps that the track change starts now */
509 audio_post_track_change(false);
498 510
499static void start_processed_track_change(bool auto_skip) 511 /* Can't do two crossfades at once and, no fade if pcm is off now */
500{ 512 if (
501 logf(" processed track change");
502 /* Notify the wps that the track change starts now */
503 audio_post_track_change(false);
504
505 /* Can't do two crossfades at once and, no fade if pcm is off now */
506 if (
507#ifdef HAVE_CROSSFADE 513#ifdef HAVE_CROSSFADE
508 pcmbuf_is_crossfade_active() || 514 pcmbuf_is_crossfade_active() ||
509#endif 515#endif
510 !pcm_is_playing()) 516 !pcm_is_playing())
511 { 517 {
512 pcmbuf_play_stop(); 518 pcmbuf_play_stop();
513 return; 519 return;
514 } 520 }
515 521
516 trigger_cpu_boost(); 522 trigger_cpu_boost();
517 523
518 /* Not enough data, or crossfade disabled, flush the old data instead */ 524 /* Not enough data, or not crossfading, flush the old data instead */
519 if (LOW_DATA(2) || 525 if (LOW_DATA(2) || !crossfade || low_latency_mode)
520#ifdef HAVE_CROSSFADE 526 {
521 !pcmbuf_is_crossfade_enabled() || 527 flush_pcmbuf = true;
522#endif 528 commit_chunk();
523 low_latency_mode) 529 return;
524 { 530 }
525 /* commit everything to this point and keep going, but... */
526 commit_chunk();
527 /* ... when the next chunk commits, throw away everything but itself */
528 flush_pcmbuf = true;
529 return;
530 }
531 531
532#ifdef HAVE_CROSSFADE 532#ifdef HAVE_CROSSFADE
533 /* Don't enable mix mode when skipping tracks manually. */ 533 /* Don't enable mix mode when skipping tracks manually. */
534 crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode; 534 crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode;
535 535
536 crossfade_track_change_started = true; 536 crossfade_track_change_started = crossfade;
537#else
538 (void)auto_skip;
539#endif 537#endif
540} 538 }
541 539 else /* automatic and not crossfading, so gapless track change */
542void pcmbuf_start_track_change(bool auto_skip)
543{
544 bool process = false;
545 /* Manual track change (always crossfade or flush audio). */
546 if (!auto_skip)
547 process = true;
548
549#ifdef HAVE_CROSSFADE
550 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
551 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
552 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
553 { 540 {
554 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP) 541 /* The codec is moving on to the next track, but the current track will
555 { 542 * continue to play. Set a flag to make sure the elapsed time of the
556 if (global_settings.playlist_shuffle) 543 * current track will be updated properly, and mark the current chunk
557 process = true; 544 * as the last one in the track. */
558 } 545 logf(" gapless track change");
559 else 546 track_transition = true;
560 process = true; 547 end_of_track = true;
561 } 548 }
562#endif
563
564 if (process)
565 /* process track change (manual skip or crossfade) */
566 start_processed_track_change(auto_skip);
567 else
568 /* normal gapless playback */
569 start_gapless_track_change();
570}
571
572/* Called when the last chunk in the track has been played */
573static void finish_gapless_track_change(void)
574{
575 /* not in a track transition anymore */
576 if(track_transition){logf("pcmbuf: (finish change) track transition false");}
577 track_transition = false;
578
579 /* notify playback that the track has just finished */
580 audio_post_track_change(true);
581} 549}
582 550
583 551
@@ -586,28 +554,31 @@ static void finish_gapless_track_change(void)
586/** PCM driver callback 554/** PCM driver callback
587 * This function has 3 major logical parts (separated by brackets both for 555 * This function has 3 major logical parts (separated by brackets both for
588 * readability and variable scoping). The first part performs the 556 * readability and variable scoping). The first part performs the
589 * operations related to finishing off the last buffer we fed to the DMA. 557 * operations related to finishing off the last chunk we fed to the DMA.
590 * The second part detects the end of playlist condition when the pcm 558 * The second part detects the end of playlist condition when the PCM
591 * buffer is empty except for uncommitted samples. Then they are committed. 559 * buffer is empty except for uncommitted samples. Then they are committed
592 * The third part performs the operations involved in sending a new buffer 560 * and sent to the PCM driver for playback. The third part performs the
593 * to the DMA. */ 561 * operations involved in sending a new chunk to the DMA. */
594static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; 562static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR;
595static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) 563static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
596{ 564{
597 { 565 {
598 struct chunkdesc *pcmbuf_current = read_chunk; 566 struct chunkdesc *pcmbuf_current = read_chunk;
599 /* Take the finished buffer out of circulation */ 567 /* Take the finished chunk out of circulation */
600 read_chunk = pcmbuf_current->link; 568 read_chunk = pcmbuf_current->link;
601 569
602 /* if during a track transition, update the elapsed time */ 570 /* if during a track transition, update the elapsed time */
603 if (track_transition) 571 if (track_transition)
604 audio_pcmbuf_position_callback(last_chunksize); 572 audio_pcmbuf_position_callback(last_chunksize);
605 573
606 /* if last buffer in the track, let the audio thread know */ 574 /* if last chunk in the track, stop updates and notify audio thread */
607 if (pcmbuf_current->end_of_track) 575 if (pcmbuf_current->end_of_track)
608 finish_gapless_track_change(); 576 {
577 track_transition = false;
578 audio_post_track_change(true);
579 }
609 580
610 /* Put the finished buffer back into circulation */ 581 /* Put the finished chunk back into circulation */
611 write_end_chunk->link = pcmbuf_current; 582 write_end_chunk->link = pcmbuf_current;
612 write_end_chunk = pcmbuf_current; 583 write_end_chunk = pcmbuf_current;
613 584
@@ -632,7 +603,7 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
632 } 603 }
633 604
634 { 605 {
635 /* Send the new buffer to the pcm */ 606 /* Send the new chunk to the PCM */
636 if(read_chunk) 607 if(read_chunk)
637 { 608 {
638 size_t current_size = read_chunk->size; 609 size_t current_size = read_chunk->size;
@@ -644,12 +615,11 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
644 } 615 }
645 else 616 else
646 { 617 {
647 /* No more buffers */ 618 /* No more chunks */
619 logf("pcmbuf_pcm_callback: no more chunks");
648 last_chunksize = 0; 620 last_chunksize = 0;
649 *size = 0; 621 *size = 0;
650 *start = NULL; 622 *start = NULL;
651 if (end_of_track)
652 finish_gapless_track_change();
653 } 623 }
654 } 624 }
655 DISPLAY_DESC("callback"); 625 DISPLAY_DESC("callback");
@@ -660,6 +630,7 @@ void pcmbuf_play_start(void)
660{ 630{
661 if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL) 631 if (!pcm_is_playing() && pcmbuf_unplayed_bytes && read_chunk != NULL)
662 { 632 {
633 logf("pcmbuf_play_start");
663 last_chunksize = read_chunk->size; 634 last_chunksize = read_chunk->size;
664 pcmbuf_unplayed_bytes -= last_chunksize; 635 pcmbuf_unplayed_bytes -= last_chunksize;
665 pcm_play_data(pcmbuf_pcm_callback, 636 pcm_play_data(pcmbuf_pcm_callback,
@@ -669,6 +640,7 @@ void pcmbuf_play_start(void)
669 640
670void pcmbuf_play_stop(void) 641void pcmbuf_play_stop(void)
671{ 642{
643 logf("pcmbuf_play_stop");
672 pcm_play_stop(); 644 pcm_play_stop();
673 645
674 pcmbuf_unplayed_bytes = 0; 646 pcmbuf_unplayed_bytes = 0;
@@ -684,6 +656,8 @@ void pcmbuf_play_stop(void)
684 crossfade_track_change_started = false; 656 crossfade_track_change_started = false;
685 crossfade_active = false; 657 crossfade_active = false;
686#endif 658#endif
659 end_of_track = false;
660 track_transition = false;
687 flush_pcmbuf = false; 661 flush_pcmbuf = false;
688 DISPLAY_DESC("play_stop"); 662 DISPLAY_DESC("play_stop");
689 663
@@ -693,6 +667,7 @@ void pcmbuf_play_stop(void)
693 667
694void pcmbuf_pause(bool pause) 668void pcmbuf_pause(bool pause)
695{ 669{
670 logf("pcmbuf_pause: %s", pause?"pause":"play");
696 if (pcm_is_playing()) 671 if (pcm_is_playing())
697 pcm_play_pause(!pause); 672 pcm_play_pause(!pause);
698 else if (!pause) 673 else if (!pause)