diff options
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r-- | apps/pcmbuf.c | 193 |
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 | 471 | void 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. */ | ||
479 | static 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 |
490 | static 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 | ||
499 | static 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 */ | |
542 | void 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 */ | ||
573 | static 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. */ |
594 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; | 562 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; |
595 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) | 563 | static 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 | ||
670 | void pcmbuf_play_stop(void) | 641 | void 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 | ||
694 | void pcmbuf_pause(bool pause) | 668 | void 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) |