diff options
-rw-r--r-- | apps/pcmbuf.c | 207 |
1 files changed, 98 insertions, 109 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index cda20d9f48..02c307df72 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -68,10 +68,8 @@ struct chunkdesc | |||
68 | bool end_of_track; | 68 | bool end_of_track; |
69 | }; | 69 | }; |
70 | 70 | ||
71 | #define CHUNK_DESCS(bufsize) \ | 71 | #define NUM_CHUNK_DESCS(bufsize) \ |
72 | ((bufsize) / PCMBUF_MINAVG_CHUNK) | 72 | ((bufsize) / PCMBUF_MINAVG_CHUNK) |
73 | #define CHUNK_DESCS_SIZE(bufsize) \ | ||
74 | (CHUNK_DESCS(bufsize)*sizeof(struct chunkdesc)) | ||
75 | 73 | ||
76 | /* Size of the PCM buffer. */ | 74 | /* Size of the PCM buffer. */ |
77 | static size_t pcmbuf_size IDATA_ATTR = 0; | 75 | static size_t pcmbuf_size IDATA_ATTR = 0; |
@@ -132,7 +130,6 @@ extern unsigned int codec_thread_id; | |||
132 | #define LOW_DATA(quarter_secs) \ | 130 | #define LOW_DATA(quarter_secs) \ |
133 | (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs) | 131 | (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs) |
134 | 132 | ||
135 | static void finish_gapless_track_change(void); | ||
136 | #ifdef HAVE_CROSSFADE | 133 | #ifdef HAVE_CROSSFADE |
137 | static void crossfade_start(void); | 134 | static void crossfade_start(void); |
138 | static void flush_crossfade(char *buf, size_t length); | 135 | static void flush_crossfade(char *buf, size_t length); |
@@ -432,22 +429,17 @@ static size_t get_next_required_pcmbuf_size(void) | |||
432 | return seconds * (NATIVE_FREQUENCY*4); /* 2 channels + 2 bytes/sample */ | 429 | return seconds * (NATIVE_FREQUENCY*4); /* 2 channels + 2 bytes/sample */ |
433 | } | 430 | } |
434 | 431 | ||
435 | static char *pcmbuf_calc_pcmbuffer_ptr(size_t bufsize) | ||
436 | { | ||
437 | return pcmbuf_bufend - (bufsize + PCMBUF_MIX_CHUNK * 2 + | ||
438 | CHUNK_DESCS_SIZE(bufsize)); | ||
439 | } | ||
440 | |||
441 | /* Initialize the pcmbuffer the structure looks like this: | 432 | /* Initialize the pcmbuffer the structure looks like this: |
442 | * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ | 433 | * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ |
443 | size_t pcmbuf_init(unsigned char *bufend) | 434 | size_t pcmbuf_init(unsigned char *bufend) |
444 | { | 435 | { |
445 | pcmbuf_bufend = bufend; | 436 | pcmbuf_bufend = bufend; |
446 | pcmbuf_size = get_next_required_pcmbuf_size(); | 437 | pcmbuf_size = get_next_required_pcmbuf_size(); |
447 | pcmbuffer = pcmbuf_calc_pcmbuffer_ptr(pcmbuf_size); | 438 | write_chunk = (struct chunkdesc *)pcmbuf_bufend - |
448 | fadebuf = &pcmbuffer[pcmbuf_size]; | 439 | NUM_CHUNK_DESCS(pcmbuf_size); |
449 | voicebuf = &fadebuf[PCMBUF_MIX_CHUNK]; | 440 | voicebuf = (char *)write_chunk - PCMBUF_MIX_CHUNK; |
450 | write_chunk = (struct chunkdesc *)&voicebuf[PCMBUF_MIX_CHUNK]; | 441 | fadebuf = voicebuf - PCMBUF_MIX_CHUNK; |
442 | pcmbuffer = fadebuf - pcmbuf_size; | ||
451 | 443 | ||
452 | init_pcmbuffers(); | 444 | init_pcmbuffers(); |
453 | 445 | ||
@@ -463,6 +455,91 @@ size_t pcmbuf_init(unsigned char *bufend) | |||
463 | } | 455 | } |
464 | 456 | ||
465 | 457 | ||
458 | /* Track change */ | ||
459 | |||
460 | /* The codec is moving on to the next track, but the current track is | ||
461 | * still playing. Set flags to make sure the elapsed time of the current | ||
462 | * track is updated properly, and mark the currently written chunk as the | ||
463 | * last one in the track. */ | ||
464 | static void start_gapless_track_change(void) | ||
465 | { | ||
466 | /* we're starting a track transition */ | ||
467 | track_transition = true; | ||
468 | |||
469 | /* mark the last chunk in the track */ | ||
470 | end_of_track = true; | ||
471 | } | ||
472 | |||
473 | static void start_crossfade_track_change(bool auto_skip) | ||
474 | { | ||
475 | /* Notify the wps that the track change starts now */ | ||
476 | audio_post_track_change(false); | ||
477 | |||
478 | /* Can't do two crossfades at once and, no fade if pcm is off now */ | ||
479 | if (pcmbuf_is_crossfade_active() || !pcm_is_playing()) | ||
480 | { | ||
481 | pcmbuf_play_stop(); | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | trigger_cpu_boost(); | ||
486 | |||
487 | /* Not enough data, or crossfade disabled, flush the old data instead */ | ||
488 | if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode) | ||
489 | { | ||
490 | /* commit everything to this point and keep going, but... */ | ||
491 | commit_chunk(); | ||
492 | /* ... when the next chunk commits, throw away everything but itself */ | ||
493 | flush_pcmbuf = true; | ||
494 | return; | ||
495 | } | ||
496 | |||
497 | /* Don't enable mix mode when skipping tracks manually. */ | ||
498 | crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode; | ||
499 | |||
500 | crossfade_track_change_started = true; | ||
501 | } | ||
502 | |||
503 | void pcmbuf_start_track_change(bool auto_skip) | ||
504 | { | ||
505 | /* Manual track change (always crossfade or flush audio). */ | ||
506 | if (!auto_skip) | ||
507 | start_crossfade_track_change(false); | ||
508 | |||
509 | /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */ | ||
510 | else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active() | ||
511 | && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP) | ||
512 | { | ||
513 | if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP) | ||
514 | { | ||
515 | if (global_settings.playlist_shuffle) | ||
516 | /* shuffle mode is on, so crossfade: */ | ||
517 | start_crossfade_track_change(true); | ||
518 | else | ||
519 | /* shuffle mode is off, so normal gapless playback */ | ||
520 | start_gapless_track_change(); | ||
521 | } | ||
522 | else | ||
523 | /* normal crossfade: */ | ||
524 | start_crossfade_track_change(true); | ||
525 | } | ||
526 | else | ||
527 | /* normal gapless playback. */ | ||
528 | start_gapless_track_change(); | ||
529 | } | ||
530 | |||
531 | /* Called when the last chunk in the track has been played */ | ||
532 | static void finish_gapless_track_change(void) | ||
533 | { | ||
534 | /* not in a track transition anymore */ | ||
535 | if(track_transition){logf("pcmbuf: (finish change) track transition false");} | ||
536 | track_transition = false; | ||
537 | |||
538 | /* notify playback that the track has just finished */ | ||
539 | audio_post_track_change(true); | ||
540 | } | ||
541 | |||
542 | |||
466 | /* Playback */ | 543 | /* Playback */ |
467 | 544 | ||
468 | /** PCM driver callback | 545 | /** PCM driver callback |
@@ -512,24 +589,21 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) | |||
512 | 589 | ||
513 | { | 590 | { |
514 | /* Send the new buffer to the pcm */ | 591 | /* Send the new buffer to the pcm */ |
515 | struct chunkdesc *pcmbuf_new = read_chunk; | 592 | if(read_chunk) |
516 | size_t *realsize = size; | ||
517 | unsigned char** realstart = start; | ||
518 | if(pcmbuf_new) | ||
519 | { | 593 | { |
520 | size_t current_size = pcmbuf_new->size; | 594 | size_t current_size = read_chunk->size; |
521 | 595 | ||
522 | pcmbuf_unplayed_bytes -= current_size; | 596 | pcmbuf_unplayed_bytes -= current_size; |
523 | last_chunksize = current_size; | 597 | last_chunksize = current_size; |
524 | *realsize = current_size; | 598 | *size = current_size; |
525 | *realstart = pcmbuf_new->addr; | 599 | *start = read_chunk->addr; |
526 | } | 600 | } |
527 | else | 601 | else |
528 | { | 602 | { |
529 | /* No more buffers */ | 603 | /* No more buffers */ |
530 | last_chunksize = 0; | 604 | last_chunksize = 0; |
531 | *realsize = 0; | 605 | *size = 0; |
532 | *realstart = NULL; | 606 | *start = NULL; |
533 | if (end_of_track) | 607 | if (end_of_track) |
534 | finish_gapless_track_change(); | 608 | finish_gapless_track_change(); |
535 | } | 609 | } |
@@ -580,91 +654,6 @@ void pcmbuf_pause(bool pause) | |||
580 | } | 654 | } |
581 | 655 | ||
582 | 656 | ||
583 | /* Track change */ | ||
584 | |||
585 | /* The codec is moving on to the next track, but the current track is | ||
586 | * still playing. Set flags to make sure the elapsed time of the current | ||
587 | * track is updated properly, and mark the currently written chunk as the | ||
588 | * last one in the track. */ | ||
589 | static void start_gapless_track_change(void) | ||
590 | { | ||
591 | /* we're starting a track transition */ | ||
592 | track_transition = true; | ||
593 | |||
594 | /* mark the last chunk in the track */ | ||
595 | end_of_track = true; | ||
596 | } | ||
597 | |||
598 | static void start_crossfade_track_change(bool auto_skip) | ||
599 | { | ||
600 | /* Notify the wps that the track change starts now */ | ||
601 | audio_post_track_change(false); | ||
602 | |||
603 | /* Can't do two crossfades at once and, no fade if pcm is off now */ | ||
604 | if (pcmbuf_is_crossfade_active() || !pcm_is_playing()) | ||
605 | { | ||
606 | pcmbuf_play_stop(); | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | trigger_cpu_boost(); | ||
611 | |||
612 | /* Not enough data, or crossfade disabled, flush the old data instead */ | ||
613 | if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode) | ||
614 | { | ||
615 | /* commit everything to this point and keep going, but... */ | ||
616 | commit_chunk(); | ||
617 | /* ... when the next chunk commits, throw away everything but itself */ | ||
618 | flush_pcmbuf = true; | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | /* Don't enable mix mode when skipping tracks manually. */ | ||
623 | crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode; | ||
624 | |||
625 | crossfade_track_change_started = true; | ||
626 | } | ||
627 | |||
628 | void pcmbuf_start_track_change(bool auto_skip) | ||
629 | { | ||
630 | /* Manual track change (always crossfade or flush audio). */ | ||
631 | if (!auto_skip) | ||
632 | start_crossfade_track_change(false); | ||
633 | |||
634 | /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */ | ||
635 | else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active() | ||
636 | && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP) | ||
637 | { | ||
638 | if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP) | ||
639 | { | ||
640 | if (global_settings.playlist_shuffle) | ||
641 | /* shuffle mode is on, so crossfade: */ | ||
642 | start_crossfade_track_change(true); | ||
643 | else | ||
644 | /* shuffle mode is off, so normal gapless playback */ | ||
645 | start_gapless_track_change(); | ||
646 | } | ||
647 | else | ||
648 | /* normal crossfade: */ | ||
649 | start_crossfade_track_change(true); | ||
650 | } | ||
651 | else | ||
652 | /* normal gapless playback. */ | ||
653 | start_gapless_track_change(); | ||
654 | } | ||
655 | |||
656 | /* Called when the last chunk in the track has been played */ | ||
657 | static void finish_gapless_track_change(void) | ||
658 | { | ||
659 | /* not in a track transition anymore */ | ||
660 | if(track_transition){logf("pcmbuf: (finish change) track transition false");} | ||
661 | track_transition = false; | ||
662 | |||
663 | /* notify playback that the track has just finished */ | ||
664 | audio_post_track_change(true); | ||
665 | } | ||
666 | |||
667 | |||
668 | /* Crossfade */ | 657 | /* Crossfade */ |
669 | 658 | ||
670 | /* Clip sample to signed 16 bit range */ | 659 | /* Clip sample to signed 16 bit range */ |
@@ -1095,7 +1084,7 @@ int pcmbuf_used_descs(void) | |||
1095 | 1084 | ||
1096 | int pcmbuf_descs(void) | 1085 | int pcmbuf_descs(void) |
1097 | { | 1086 | { |
1098 | return CHUNK_DESCS(pcmbuf_size); | 1087 | return NUM_CHUNK_DESCS(pcmbuf_size); |
1099 | } | 1088 | } |
1100 | 1089 | ||
1101 | #ifdef ROCKBOX_HAS_LOGF | 1090 | #ifdef ROCKBOX_HAS_LOGF |