summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/lang/english.lang12
-rw-r--r--apps/pcmbuf.c27
-rw-r--r--apps/pcmbuf.h2
-rw-r--r--apps/playback.c16
-rw-r--r--apps/settings.c8
-rw-r--r--apps/settings.h5
-rw-r--r--apps/settings_menu.c24
-rw-r--r--firmware/export/audio.h2
-rw-r--r--firmware/pcm_playback.c4
9 files changed, 82 insertions, 18 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index b7c829f4b8..4c38fad925 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3166,3 +3166,15 @@ desc: in set_rating
eng: "Rating:"
voice "Rating"
new:
+
+id: LANG_CROSSFADE_DURATION
+desc: in playback settings
+eng: "Crossfade duration"
+voice: "Crossfade duration"
+new:
+
+id: LANG_MIX
+desc: in playback settings, crossfade option
+eng: "Mix"
+voice: "Mix"
+new:
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index a8769e3829..691f8d5a19 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -69,6 +69,7 @@ static bool boost_mode;
*/
enum {
CFM_CROSSFADE,
+ CFM_MIX,
CFM_FLUSH
};
@@ -221,7 +222,7 @@ bool pcmbuf_is_lowdata(void)
return false;
}
-bool pcmbuf_crossfade_init(void)
+bool pcmbuf_crossfade_init(int type)
{
if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|| crossfade_active || crossfade_init) {
@@ -230,7 +231,18 @@ bool pcmbuf_crossfade_init(void)
}
logf("pcmbuf_crossfade_init");
pcmbuf_boost(true);
- crossfade_mode = CFM_CROSSFADE;
+
+ switch (type) {
+ case CROSSFADE_MODE_CROSSFADE:
+ crossfade_mode = CFM_CROSSFADE;
+ break;
+ case CROSSFADE_MODE_MIX:
+ crossfade_mode = CFM_MIX;
+ break;
+ default:
+ return false;
+ }
+
crossfade_init = true;
return true;
@@ -330,6 +342,7 @@ static void crossfade_start(void)
crossfade_pos = audiobuffer_pos;
switch (crossfade_mode) {
+ case CFM_MIX:
case CFM_CROSSFADE:
crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2;
crossfade_rem = crossfade_amount;
@@ -354,6 +367,15 @@ int crossfade(short *buf, const short *buf2, int length)
size = MIN(length, crossfade_rem);
switch (crossfade_mode) {
+ /* Mix two streams. */
+ case CFM_MIX:
+ /* Bias & add & clip. */
+ for (i = 0; i < size; i++) {
+ buf[i] = MIN(MAX(buf[i] + buf2[i], -32768), 32767);
+ }
+ break ;
+
+ /* Fade two streams. */
case CFM_CROSSFADE:
val1 = (crossfade_rem<<10)/crossfade_amount;
val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
@@ -363,6 +385,7 @@ int crossfade(short *buf, const short *buf2, int length)
}
break ;
+ /* Join two streams. */
case CFM_FLUSH:
for (i = 0; i < size; i++) {
buf[i] = buf2[i];
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 29217afc9b..6381dbc27e 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -36,7 +36,7 @@ void pcmbuf_set_watermark(int numbytes, void (*callback)(int bytes_left));
void pcmbuf_set_boost_mode(bool state);
bool pcmbuf_is_lowdata(void);
void pcmbuf_flush_audio(void);
-bool pcmbuf_crossfade_init(void);
+bool pcmbuf_crossfade_init(int type);
void pcmbuf_add_event(void (*event_handler)(void));
unsigned int pcmbuf_get_latency(void);
bool pcmbuf_insert_buffer(char *buf, long length);
diff --git a/apps/playback.c b/apps/playback.c
index 7aaff01e54..f502d8291b 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1175,7 +1175,8 @@ void audio_update_trackinfo(void)
cur_ti->start_pos = 0;
ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) {
- pcmbuf_crossfade_init();
+ pcmbuf_crossfade_init(new_track ? CROSSFADE_MODE_CROSSFADE
+ : global_settings.crossfade);
codec_track_changed();
} else {
pcmbuf_add_event(codec_track_changed);
@@ -1393,7 +1394,7 @@ void audio_thread(void)
ci.stop_codec = true;
ci.reload_codec = false;
ci.seek_time = 0;
- pcmbuf_crossfade_init();
+ pcmbuf_crossfade_init(CROSSFADE_MODE_CROSSFADE);
while (codec_loaded)
yield();
audio_play_start((int)ev.data);
@@ -1771,19 +1772,22 @@ void audio_set_buffer_margin(int setting)
set_filebuf_watermark(buffer_margin);
}
-void audio_set_crossfade_amount(int seconds)
+/* Set crossfade & PCM buffer length. */
+void audio_set_crossfade(int type)
{
long size;
bool was_playing = playing;
int offset = 0;
+ int lookup[] = {1, 2, 4, 6, 8, 10, 12, 14};
+ int seconds = lookup[global_settings.crossfade_duration];
/* Store the track resume position */
if (playing)
offset = cur_ti->id3.offset;
- /* Multiply by two to get the real value (0s, 2s, 4s, ...) */
- seconds *= 2;
-
+ if (type == CROSSFADE_MODE_OFF)
+ seconds = 0;
+
/* Buffer has to be at least 2s long. */
seconds += 2;
logf("buf len: %d", seconds);
diff --git a/apps/settings.c b/apps/settings.c
index d374f00ff2..efb9cfd9de 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -397,7 +397,7 @@ static const struct bit_entry hd_bits[] =
#endif
#if CONFIG_HWCODEC == MASNONE
- {3, S_O(crossfade), 0, "crossfade", "off,2s,4s,6s,8s,10s,12s,14s"},
+ {3, S_O(crossfade_duration), 0, "crossfade duration", "1s,2s,4s,6s,8s,10s,12s,14s"},
#endif
#if CONFIG_BACKLIGHT == BL_IRIVER
@@ -414,6 +414,10 @@ static const struct bit_entry hd_bits[] =
{1, S_O(next_folder), false, "move to next folder", off_on },
{1, S_O(runtimedb), false, "gather runtime data", off_on },
+#if CONFIG_HWCODEC == MASNONE
+ {2, S_O(crossfade), 0, "crossfade type", "off,crossfade,mix"},
+#endif
+
/* new stuff to be added at the end */
/* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
@@ -851,7 +855,7 @@ void settings_apply(void)
}
#if CONFIG_HWCODEC == MASNONE
- audio_set_crossfade_amount(global_settings.crossfade);
+ audio_set_crossfade(global_settings.crossfade);
#endif
#ifdef HAVE_SPDIF_POWER
diff --git a/apps/settings.h b/apps/settings.h
index 14c8347d3c..3e3a982b94 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -106,6 +106,10 @@
#define TRIG_DURATION_COUNT 13
extern char *trig_durations[TRIG_DURATION_COUNT];
+#define CROSSFADE_MODE_OFF 0
+#define CROSSFADE_MODE_CROSSFADE 1
+#define CROSSFADE_MODE_MIX 2
+
/* These define "virtual pointers", which could either be a literal string,
or a mean a string ID if the pointer is in a certain range.
This helps to save space for menus and options. */
@@ -151,6 +155,7 @@ struct user_settings
#if CONFIG_HWCODEC == MASNONE
int crossfade;
+ int crossfade_duration;
#endif
int rec_quality; /* 0-7 */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index df5f4a49ae..5b03a8d22e 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1131,6 +1131,22 @@ static bool crossfade(void)
{
static const struct opt_items names[] = {
{ STR(LANG_OFF) },
+ { STR(LANG_CROSSFADE) },
+ { STR(LANG_MIX) },
+ };
+ bool ret;
+
+ ret = set_option( str(LANG_CROSSFADE),
+ &global_settings.crossfade, INT, names, 3, NULL);
+ audio_set_crossfade(global_settings.crossfade);
+
+ return ret;
+}
+
+static bool crossfade_duration(void)
+{
+ static const struct opt_items names[] = {
+ { "1s", TALK_ID(1, UNIT_SEC) },
{ "2s", TALK_ID(2, UNIT_SEC) },
{ "4s", TALK_ID(4, UNIT_SEC) },
{ "6s", TALK_ID(6, UNIT_SEC) },
@@ -1140,13 +1156,12 @@ static bool crossfade(void)
{ "14s", TALK_ID(14, UNIT_SEC) },
};
bool ret;
- ret=set_option( str(LANG_CROSSFADE), &global_settings.crossfade,
- INT, names, 8, NULL);
- audio_set_crossfade_amount(global_settings.crossfade);
+ ret=set_option( str(LANG_CROSSFADE_DURATION),
+ &global_settings.crossfade_duration, INT, names, 8, NULL);
+ audio_set_crossfade(global_settings.crossfade);
return ret;
}
-
#endif
static bool next_folder(void)
@@ -1187,6 +1202,7 @@ static bool playback_settings_menu(void)
{ ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
#if CONFIG_HWCODEC == MASNONE
{ ID2P(LANG_CROSSFADE), crossfade },
+ { ID2P(LANG_CROSSFADE_DURATION), crossfade_duration },
#endif
#ifdef HAVE_SPDIF_POWER
{ ID2P(LANG_SPDIF_ENABLE), spdif },
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index c8746c1aac..17de7f077d 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -71,7 +71,7 @@ struct mp3entry* audio_current_track(void);
struct mp3entry* audio_next_track(void);
bool audio_has_changed_track(void);
void audio_get_debugdata(struct audio_debug *dbgdata);
-void audio_set_crossfade_amount(int seconds);
+void audio_set_crossfade(int type);
void audio_set_buffer_margin(int seconds);
unsigned int audio_error(void);
void audio_error_clear(void);
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index bafbd8c761..9bba88eb73 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -286,7 +286,7 @@ void DMA0(void)
/* Stop on error */
if(res & 0x70)
{
- dma_stop();
+ pcm_play_stop();
logf("DMA Error:0x%04x", res);
}
else
@@ -302,7 +302,7 @@ void DMA0(void)
else
{
/* Finished playing */
- dma_stop();
+ pcm_play_stop();
logf("DMA No Data:0x%04x", res);
}
}