summaryrefslogtreecommitdiff
path: root/apps/pcmbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r--apps/pcmbuf.c207
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. */
77static size_t pcmbuf_size IDATA_ATTR = 0; 75static 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
135static void finish_gapless_track_change(void);
136#ifdef HAVE_CROSSFADE 133#ifdef HAVE_CROSSFADE
137static void crossfade_start(void); 134static void crossfade_start(void);
138static void flush_crossfade(char *buf, size_t length); 135static 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
435static 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|... */
443size_t pcmbuf_init(unsigned char *bufend) 434size_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. */
464static 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
473static 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
503void 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 */
532static 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. */
589static 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
598static 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
628void 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 */
657static 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
1096int pcmbuf_descs(void) 1085int 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