summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/codec_thread.c44
-rw-r--r--apps/pcmbuf.c214
-rw-r--r--apps/pcmbuf.h69
-rw-r--r--apps/playback.c26
-rw-r--r--apps/playback.h2
5 files changed, 177 insertions, 178 deletions
diff --git a/apps/codec_thread.c b/apps/codec_thread.c
index fbcb23179d..e3f190e69c 100644
--- a/apps/codec_thread.c
+++ b/apps/codec_thread.c
@@ -416,47 +416,7 @@ void codec_init_codec_api(void)
}
-/** track change functions */
-
-static inline void codec_crossfade_track_change(void)
-{
- /* Initiate automatic crossfade mode */
- pcmbuf_crossfade_init(false);
- /* Notify the wps that the track change starts now */
- LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
- queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
-}
-
-static void codec_track_skip_done(bool was_manual)
-{
- /* Manual track change (always crossfade or flush audio). */
- if (was_manual)
- {
- pcmbuf_crossfade_init(true);
- LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
- queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
- }
- /* 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: */
- codec_crossfade_track_change();
- else
- /* shuffle mode is off, so normal gapless playback */
- pcmbuf_start_track_change();
- }
- else
- /* normal crossfade: */
- codec_crossfade_track_change();
- }
- else
- /* normal gapless playback. */
- pcmbuf_start_track_change();
-}
+/* track change */
static bool codec_load_next_track(void)
{
@@ -487,7 +447,7 @@ static bool codec_load_next_track(void)
{
case Q_CODEC_REQUEST_COMPLETE:
LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
- codec_track_skip_done(!automatic_skip);
+ pcmbuf_start_track_change(!automatic_skip);
return true;
case Q_CODEC_REQUEST_FAILED:
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index c8f89d9af9..1e286fafc6 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -49,6 +49,17 @@ static inline int32_t clip_sample_16(int32_t sample)
return sample;
}
+#define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
+ on the pcm buffer */
+#define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
+ chunks on the pcm buffer (or we run out
+ of buffer descriptors, which is
+ non-fatal) */
+#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
+ this to the DMA */
+#define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet
+ for mixing (crossfade or voice) */
+
#if MEMORYSIZE > 2
/* Keep watermark high for iPods at least (2s) */
#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 4 * 2)
@@ -135,6 +146,10 @@ static bool prepare_insert(size_t length);
static void pcmbuf_under_watermark(bool under);
static bool pcmbuf_flush_fillpos(void);
+static bool pcmbuf_crossfade_init(bool manual_skip);
+static bool pcmbuf_is_crossfade_enabled(void);
+static void pcmbuf_finish_crossfade_enable(void);
+
/**************************************/
@@ -181,7 +196,7 @@ static bool show_desc(char *caller)
* 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. */
-void pcmbuf_start_track_change(void)
+static void pcmbuf_gapless_track_change(void)
{
/* we're starting a track transition */
track_transition = true;
@@ -190,6 +205,44 @@ void pcmbuf_start_track_change(void)
end_of_track = true;
}
+static void pcmbuf_crossfade_track_change(void)
+{
+ /* Initiate automatic crossfade mode */
+ pcmbuf_crossfade_init(false);
+ /* Notify the wps that the track change starts now */
+ audio_post_track_change(false);
+}
+
+void pcmbuf_start_track_change(bool manual_skip)
+{
+ /* Manual track change (always crossfade or flush audio). */
+ if (manual_skip)
+ {
+ pcmbuf_crossfade_init(true);
+ audio_post_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: */
+ pcmbuf_crossfade_track_change();
+ else
+ /* shuffle mode is off, so normal gapless playback */
+ pcmbuf_gapless_track_change();
+ }
+ else
+ /* normal crossfade: */
+ pcmbuf_crossfade_track_change();
+ }
+ else
+ /* normal gapless playback. */
+ pcmbuf_gapless_track_change();
+}
+
/* Called when the last chunk in the track has been played */
static void pcmbuf_finish_track_change(void)
{
@@ -198,7 +251,7 @@ static void pcmbuf_finish_track_change(void)
track_transition = false;
/* notify playback that the track has just finished */
- audio_post_track_change();
+ audio_post_track_change(true);
}
@@ -274,15 +327,6 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
DISPLAY_DESC("callback");
}
-static void pcmbuf_set_watermark_bytes(void)
-{
- pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
- /* If crossfading, try to keep the buffer full other than 1 second */
- (pcmbuf_size - (NATIVE_FREQUENCY * 4 * 1)) :
- /* Otherwise, just use the default */
- PCMBUF_WATERMARK;
-}
-
/* This is really just part of pcmbuf_flush_fillpos, but is easier to keep
* in a separate function for the moment */
static inline void pcmbuf_add_chunk(void)
@@ -330,6 +374,28 @@ static inline void pcmbuf_add_chunk(void)
DISPLAY_DESC("add_chunk");
}
+/**
+ * Commit samples waiting to the pcm buffer.
+ */
+static bool pcmbuf_flush_fillpos(void)
+{
+ if (audiobuffer_fillpos) {
+ /* Never use the last buffer descriptor */
+ while (pcmbuf_write == pcmbuf_write_end) {
+ /* If this happens, something is being stupid */
+ if (!pcm_is_playing()) {
+ logf("pcmbuf_flush_fillpos error");
+ pcmbuf_play_start();
+ }
+ /* Let approximately one chunk of data playback */
+ sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
+ }
+ pcmbuf_add_chunk();
+ return true;
+ }
+ return false;
+}
+
#ifdef HAVE_PRIORITY_SCHEDULING
static void boost_codec_thread(bool boost)
{
@@ -431,7 +497,7 @@ inline size_t pcmbuf_free(void)
return pcmbuf_size;
}
-bool pcmbuf_crossfade_init(bool manual_skip)
+static bool pcmbuf_crossfade_init(bool manual_skip)
{
/* Can't do two crossfades at once and, no fade if pcm is off now */
if (crossfade_init || crossfade_active || !pcm_is_playing())
@@ -542,11 +608,20 @@ static char *pcmbuf_calc_audiobuffer_ptr(size_t bufsize)
bool pcmbuf_is_same_size(void)
{
+ bool same_size;
+
if (audiobuffer == NULL)
- return true; /* Not set up yet even once so always */
-
- size_t bufsize = pcmbuf_get_next_required_pcmbuf_size();
- return pcmbuf_calc_audiobuffer_ptr(bufsize) == audiobuffer;
+ same_size = true; /* Not set up yet even once so always */
+ else
+ {
+ size_t bufsize = pcmbuf_get_next_required_pcmbuf_size();
+ same_size = pcmbuf_calc_audiobuffer_ptr(bufsize) == audiobuffer;
+ }
+
+ if (same_size)
+ pcmbuf_finish_crossfade_enable();
+
+ return same_size;
}
/* Initialize the pcmbuffer the structure looks like this:
@@ -566,7 +641,7 @@ size_t pcmbuf_init(unsigned char *bufend)
end_of_track = false;
track_transition = false;
- pcmbuf_crossfade_enable_finished();
+ pcmbuf_finish_crossfade_enable();
pcmbuf_play_stop();
@@ -606,28 +681,6 @@ void pcmbuf_play_start(void)
}
}
-/**
- * Commit samples waiting to the pcm buffer.
- */
-static bool pcmbuf_flush_fillpos(void)
-{
- if (audiobuffer_fillpos) {
- /* Never use the last buffer descriptor */
- while (pcmbuf_write == pcmbuf_write_end) {
- /* If this happens, something is being stupid */
- if (!pcm_is_playing()) {
- logf("pcmbuf_flush_fillpos error");
- pcmbuf_play_start();
- }
- /* Let approximately one chunk of data playback */
- sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
- }
- pcmbuf_add_chunk();
- return true;
- }
- return false;
-}
-
/**
* Low memory targets don't have crossfade, so don't compile crossfade
* specific code in order to save some memory. */
@@ -907,7 +960,7 @@ static bool prepare_insert(size_t length)
return true;
}
-void* pcmbuf_request_buffer(int *count)
+void *pcmbuf_request_buffer(int *count)
{
#ifdef HAVE_CROSSFADE
if (crossfade_init)
@@ -943,38 +996,6 @@ void* pcmbuf_request_buffer(int *count)
}
}
-void * pcmbuf_request_voice_buffer(int *count)
-{
- /* A get-it-to-work-for-now hack (audio status could change by
- completion) */
- if (audio_status() & AUDIO_STATUS_PLAY)
- {
- if (pcmbuf_read == NULL)
- {
- return NULL;
- }
- else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 &&
- (pcmbuf_mix_chunk || pcmbuf_read->link))
- {
- *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
- return voicebuf;
- }
- else
- {
- return NULL;
- }
- }
- else
- {
- return pcmbuf_request_buffer(count);
- }
-}
-
-bool pcmbuf_is_crossfade_active(void)
-{
- return crossfade_active || crossfade_init;
-}
-
void pcmbuf_write_complete(int count)
{
size_t length = (size_t)(unsigned int)count << 2;
@@ -1098,12 +1119,12 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
#endif /* HAVE_HARDWARE_BEEP */
/* Returns pcm buffer usage in percents (0 to 100). */
-int pcmbuf_usage(void)
+static int pcmbuf_usage(void)
{
return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
}
-int pcmbuf_mix_free(void)
+static int pcmbuf_mix_free(void)
{
if (pcmbuf_mix_chunk)
{
@@ -1117,6 +1138,33 @@ int pcmbuf_mix_free(void)
return 100;
}
+void *pcmbuf_request_voice_buffer(int *count)
+{
+ /* A get-it-to-work-for-now hack (audio status could change by
+ completion) */
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ {
+ if (pcmbuf_read == NULL)
+ {
+ return NULL;
+ }
+ else if (pcmbuf_usage() >= 10 && pcmbuf_mix_free() >= 30 &&
+ (pcmbuf_mix_chunk || pcmbuf_read->link))
+ {
+ *count = MIN(*count, PCMBUF_MIX_CHUNK/4);
+ return voicebuf;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ return pcmbuf_request_buffer(count);
+ }
+}
+
void pcmbuf_write_voice_complete(int count)
{
/* A get-it-to-work-for-now hack (audio status could have changed) */
@@ -1163,23 +1211,33 @@ void pcmbuf_write_voice_complete(int count)
}
}
-void pcmbuf_crossfade_enable(bool on_off)
+void pcmbuf_request_crossfade_enable(bool on_off)
{
/* Next setting to be used, not applied now */
crossfade_enabled_pending = on_off;
}
-void pcmbuf_crossfade_enable_finished(void)
+static void pcmbuf_finish_crossfade_enable(void)
{
/* Copy the pending setting over now */
crossfade_enabled = crossfade_enabled_pending;
- pcmbuf_set_watermark_bytes();
+
+ pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ?
+ /* If crossfading, try to keep the buffer full other than 1 second */
+ (pcmbuf_size - (NATIVE_FREQUENCY * 4 * 1)) :
+ /* Otherwise, just use the default */
+ PCMBUF_WATERMARK;
}
-bool pcmbuf_is_crossfade_enabled(void)
+static bool pcmbuf_is_crossfade_enabled(void)
{
if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE)
return global_settings.playlist_shuffle;
return crossfade_enabled;
}
+
+bool pcmbuf_is_crossfade_active(void)
+{
+ return crossfade_active || crossfade_init;
+}
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 1d893f9c62..f8e69055be 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -21,58 +21,37 @@
#ifndef PCMBUF_H
#define PCMBUF_H
-#define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
- on the pcm buffer */
-#define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
- chunks on the pcm buffer (or we run out
- of buffer descriptors, which is
- non-fatal) */
-#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
- this to the DMA */
-#define PCMBUF_MIX_CHUNK 8192 /* This is the maximum size of one packet
- for mixing (crossfade or voice) */
+/* playback */
+size_t pcmbuf_init(unsigned char *bufend);
+void pcmbuf_play_start(void);
+void pcmbuf_play_stop(void);
+void pcmbuf_pause(bool pause);
+void pcmbuf_start_track_change(bool manual_skip);
+void *pcmbuf_request_buffer(int *count);
+void pcmbuf_write_complete(int count);
-/* Returns true if the buffer needs to change size */
+/* crossfade */
+bool pcmbuf_is_crossfade_active(void);
+void pcmbuf_request_crossfade_enable(bool on_off);
bool pcmbuf_is_same_size(void);
-size_t pcmbuf_init(unsigned char *bufend);
-/* Size in bytes used by the pcmbuffer */
+
+/* voice */
+void *pcmbuf_request_voice_buffer(int *count);
+void pcmbuf_write_voice_complete(int count);
+
+/* debug menu, other metrics */
+size_t pcmbuf_free(void);
size_t pcmbuf_get_bufsize(void);
+int pcmbuf_descs(void);
+int pcmbuf_used_descs(void);
#ifdef ROCKBOX_HAS_LOGF
-/* just used for logging for now */
-unsigned char * pcmbuf_get_meminfo(size_t *length);
+unsigned char *pcmbuf_get_meminfo(size_t *length);
#endif
-void pcmbuf_pause(bool pause);
-void pcmbuf_play_stop(void);
-bool pcmbuf_is_crossfade_active(void);
-
-/* These functions are for playing chained buffers of PCM data */
-#if defined(HAVE_ADJUSTABLE_CPU_FREQ)
-void pcmbuf_boost(bool state);
-void pcmbuf_set_boost_mode(bool state);
-#else
-#define pcmbuf_boost(state) do { } while(0)
-#define pcmbuf_set_boost_mode(state) do { } while(0)
-#endif
+/* misc */
+void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude);
bool pcmbuf_is_lowdata(void);
-void pcmbuf_play_start(void);
-bool pcmbuf_crossfade_init(bool manual_skip);
-void pcmbuf_start_track_change(void);
-size_t pcmbuf_free(void);
-unsigned long pcmbuf_get_latency(void);
void pcmbuf_set_low_latency(bool state);
-void * pcmbuf_request_buffer(int *count);
-void pcmbuf_write_complete(int count);
-void * pcmbuf_request_voice_buffer(int *count);
-void pcmbuf_write_voice_complete(int count);
-bool pcmbuf_is_crossfade_enabled(void);
-void pcmbuf_crossfade_enable(bool on_off);
-void pcmbuf_crossfade_enable_finished(void);
-int pcmbuf_usage(void);
-int pcmbuf_mix_free(void);
-void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude);
-
-int pcmbuf_used_descs(void);
-int pcmbuf_descs(void);
+unsigned long pcmbuf_get_latency(void);
#endif
diff --git a/apps/playback.c b/apps/playback.c
index d3c4b46a99..fbaaa5c974 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -246,10 +246,18 @@ void audio_pcmbuf_position_callback(size_t size)
/* Post message from pcmbuf that the end of the previous track
* has just been played. */
-void audio_post_track_change(void)
+void audio_post_track_change(bool pcmbuf)
{
- LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED");
- queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
+ if (pcmbuf)
+ {
+ LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED");
+ queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
+ }
+ else
+ {
+ LOGFQUEUE("pcmbuf > audio Q_AUDIO_TRACK_CHANGED");
+ queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
+ }
}
/* Scan the pcmbuf queue and return true if a message pulled.
@@ -814,18 +822,12 @@ void audio_set_crossfade(int enable)
size_t size;
/* Tell it the next setting to use */
- pcmbuf_crossfade_enable(enable);
+ pcmbuf_request_crossfade_enable(enable);
/* Return if size hasn't changed or this is too early to determine
which in the second case there's no way we could be playing
anything at all */
- if (pcmbuf_is_same_size())
- {
- /* This function is a copout and just syncs some variables -
- to be removed at a later date */
- pcmbuf_crossfade_enable_finished();
- return;
- }
+ if (pcmbuf_is_same_size()) return;
offset = 0;
was_playing = playing;
@@ -2058,7 +2060,7 @@ void audio_init(void)
#endif
/* Set crossfade setting for next buffer init which should be about... */
- pcmbuf_crossfade_enable(global_settings.crossfade);
+ pcmbuf_request_crossfade_enable(global_settings.crossfade);
/* initialize the buffering system */
diff --git a/apps/playback.h b/apps/playback.h
index b168770361..c0fd15e590 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -70,7 +70,7 @@ enum
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
size_t audio_get_filebuflen(void);
void audio_pcmbuf_position_callback(size_t size) ICODE_ATTR;
-void audio_post_track_change(void);
+void audio_post_track_change(bool pcmbuf);
int get_audio_hid(void);
int *get_codec_hid(void);
void audio_set_prev_elapsed(unsigned long setting);