summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
bool end_of_track;
};
-#define CHUNK_DESCS(bufsize) \
+#define NUM_CHUNK_DESCS(bufsize) \
((bufsize) / PCMBUF_MINAVG_CHUNK)
-#define CHUNK_DESCS_SIZE(bufsize) \
- (CHUNK_DESCS(bufsize)*sizeof(struct chunkdesc))
/* Size of the PCM buffer. */
static size_t pcmbuf_size IDATA_ATTR = 0;
@@ -132,7 +130,6 @@ extern unsigned int codec_thread_id;
#define LOW_DATA(quarter_secs) \
(pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs)
-static void finish_gapless_track_change(void);
#ifdef HAVE_CROSSFADE
static void crossfade_start(void);
static void flush_crossfade(char *buf, size_t length);
@@ -432,22 +429,17 @@ static size_t get_next_required_pcmbuf_size(void)
return seconds * (NATIVE_FREQUENCY*4); /* 2 channels + 2 bytes/sample */
}
-static char *pcmbuf_calc_pcmbuffer_ptr(size_t bufsize)
-{
- return pcmbuf_bufend - (bufsize + PCMBUF_MIX_CHUNK * 2 +
- CHUNK_DESCS_SIZE(bufsize));
-}
-
/* Initialize the pcmbuffer the structure looks like this:
* ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
size_t pcmbuf_init(unsigned char *bufend)
{
pcmbuf_bufend = bufend;
pcmbuf_size = get_next_required_pcmbuf_size();
- pcmbuffer = pcmbuf_calc_pcmbuffer_ptr(pcmbuf_size);
- fadebuf = &pcmbuffer[pcmbuf_size];
- voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
- write_chunk = (struct chunkdesc *)&voicebuf[PCMBUF_MIX_CHUNK];
+ write_chunk = (struct chunkdesc *)pcmbuf_bufend -
+ NUM_CHUNK_DESCS(pcmbuf_size);
+ voicebuf = (char *)write_chunk - PCMBUF_MIX_CHUNK;
+ fadebuf = voicebuf - PCMBUF_MIX_CHUNK;
+ pcmbuffer = fadebuf - pcmbuf_size;
init_pcmbuffers();
@@ -463,6 +455,91 @@ size_t pcmbuf_init(unsigned char *bufend)
}
+/* Track change */
+
+/* The codec is moving on to the next track, but the current track is
+ * still playing. Set flags to make sure the elapsed time of the current
+ * track is updated properly, and mark the currently written chunk as the
+ * last one in the track. */
+static void start_gapless_track_change(void)
+{
+ /* we're starting a track transition */
+ track_transition = true;
+
+ /* mark the last chunk in the track */
+ end_of_track = true;
+}
+
+static void start_crossfade_track_change(bool auto_skip)
+{
+ /* Notify the wps that the track change starts now */
+ audio_post_track_change(false);
+
+ /* Can't do two crossfades at once and, no fade if pcm is off now */
+ if (pcmbuf_is_crossfade_active() || !pcm_is_playing())
+ {
+ pcmbuf_play_stop();
+ return;
+ }
+
+ trigger_cpu_boost();
+
+ /* Not enough data, or crossfade disabled, flush the old data instead */
+ if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode)
+ {
+ /* commit everything to this point and keep going, but... */
+ commit_chunk();
+ /* ... when the next chunk commits, throw away everything but itself */
+ flush_pcmbuf = true;
+ return;
+ }
+
+ /* Don't enable mix mode when skipping tracks manually. */
+ crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode;
+
+ crossfade_track_change_started = true;
+}
+
+void pcmbuf_start_track_change(bool auto_skip)
+{
+ /* Manual track change (always crossfade or flush audio). */
+ if (!auto_skip)
+ start_crossfade_track_change(false);
+
+ /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
+ else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
+ && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
+ {
+ if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
+ {
+ if (global_settings.playlist_shuffle)
+ /* shuffle mode is on, so crossfade: */
+ start_crossfade_track_change(true);
+ else
+ /* shuffle mode is off, so normal gapless playback */
+ start_gapless_track_change();
+ }
+ else
+ /* normal crossfade: */
+ start_crossfade_track_change(true);
+ }
+ else
+ /* normal gapless playback. */
+ start_gapless_track_change();
+}
+
+/* Called when the last chunk in the track has been played */
+static void finish_gapless_track_change(void)
+{
+ /* not in a track transition anymore */
+ if(track_transition){logf("pcmbuf: (finish change) track transition false");}
+ track_transition = false;
+
+ /* notify playback that the track has just finished */
+ audio_post_track_change(true);
+}
+
+
/* Playback */
/** PCM driver callback
@@ -512,24 +589,21 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
{
/* Send the new buffer to the pcm */
- struct chunkdesc *pcmbuf_new = read_chunk;
- size_t *realsize = size;
- unsigned char** realstart = start;
- if(pcmbuf_new)
+ if(read_chunk)
{
- size_t current_size = pcmbuf_new->size;
+ size_t current_size = read_chunk->size;
pcmbuf_unplayed_bytes -= current_size;
last_chunksize = current_size;
- *realsize = current_size;
- *realstart = pcmbuf_new->addr;
+ *size = current_size;
+ *start = read_chunk->addr;
}
else
{
/* No more buffers */
last_chunksize = 0;
- *realsize = 0;
- *realstart = NULL;
+ *size = 0;
+ *start = NULL;
if (end_of_track)
finish_gapless_track_change();
}
@@ -580,91 +654,6 @@ void pcmbuf_pause(bool pause)
}
-/* Track change */
-
-/* The codec is moving on to the next track, but the current track is
- * still playing. Set flags to make sure the elapsed time of the current
- * track is updated properly, and mark the currently written chunk as the
- * last one in the track. */
-static void start_gapless_track_change(void)
-{
- /* we're starting a track transition */
- track_transition = true;
-
- /* mark the last chunk in the track */
- end_of_track = true;
-}
-
-static void start_crossfade_track_change(bool auto_skip)
-{
- /* Notify the wps that the track change starts now */
- audio_post_track_change(false);
-
- /* Can't do two crossfades at once and, no fade if pcm is off now */
- if (pcmbuf_is_crossfade_active() || !pcm_is_playing())
- {
- pcmbuf_play_stop();
- return;
- }
-
- trigger_cpu_boost();
-
- /* Not enough data, or crossfade disabled, flush the old data instead */
- if (LOW_DATA(2) || !pcmbuf_is_crossfade_enabled() || low_latency_mode)
- {
- /* commit everything to this point and keep going, but... */
- commit_chunk();
- /* ... when the next chunk commits, throw away everything but itself */
- flush_pcmbuf = true;
- return;
- }
-
- /* Don't enable mix mode when skipping tracks manually. */
- crossfade_mixmode = auto_skip && global_settings.crossfade_fade_out_mixmode;
-
- crossfade_track_change_started = true;
-}
-
-void pcmbuf_start_track_change(bool auto_skip)
-{
- /* Manual track change (always crossfade or flush audio). */
- if (!auto_skip)
- start_crossfade_track_change(false);
-
- /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
- else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
- && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP)
- {
- if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
- {
- if (global_settings.playlist_shuffle)
- /* shuffle mode is on, so crossfade: */
- start_crossfade_track_change(true);
- else
- /* shuffle mode is off, so normal gapless playback */
- start_gapless_track_change();
- }
- else
- /* normal crossfade: */
- start_crossfade_track_change(true);
- }
- else
- /* normal gapless playback. */
- start_gapless_track_change();
-}
-
-/* Called when the last chunk in the track has been played */
-static void finish_gapless_track_change(void)
-{
- /* not in a track transition anymore */
- if(track_transition){logf("pcmbuf: (finish change) track transition false");}
- track_transition = false;
-
- /* notify playback that the track has just finished */
- audio_post_track_change(true);
-}
-
-
/* Crossfade */
/* Clip sample to signed 16 bit range */
@@ -1095,7 +1084,7 @@ int pcmbuf_used_descs(void)
int pcmbuf_descs(void)
{
- return CHUNK_DESCS(pcmbuf_size);
+ return NUM_CHUNK_DESCS(pcmbuf_size);
}
#ifdef ROCKBOX_HAS_LOGF