It's now possible to select the crossfading mode: "Off, Crossfade,
Mix". If set to mix, no fading is applied but tracks are mixed up. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7224 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4f6375ca17
commit
90161c92dd
9 changed files with 82 additions and 18 deletions
|
@ -3166,3 +3166,15 @@ desc: in set_rating
|
||||||
eng: "Rating:"
|
eng: "Rating:"
|
||||||
voice "Rating"
|
voice "Rating"
|
||||||
new:
|
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:
|
||||||
|
|
|
@ -69,6 +69,7 @@ static bool boost_mode;
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
CFM_CROSSFADE,
|
CFM_CROSSFADE,
|
||||||
|
CFM_MIX,
|
||||||
CFM_FLUSH
|
CFM_FLUSH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -221,7 +222,7 @@ bool pcmbuf_is_lowdata(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pcmbuf_crossfade_init(void)
|
bool pcmbuf_crossfade_init(int type)
|
||||||
{
|
{
|
||||||
if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|
if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|
||||||
|| crossfade_active || crossfade_init) {
|
|| crossfade_active || crossfade_init) {
|
||||||
|
@ -230,7 +231,18 @@ bool pcmbuf_crossfade_init(void)
|
||||||
}
|
}
|
||||||
logf("pcmbuf_crossfade_init");
|
logf("pcmbuf_crossfade_init");
|
||||||
pcmbuf_boost(true);
|
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;
|
crossfade_init = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -330,6 +342,7 @@ static void crossfade_start(void)
|
||||||
crossfade_pos = audiobuffer_pos;
|
crossfade_pos = audiobuffer_pos;
|
||||||
|
|
||||||
switch (crossfade_mode) {
|
switch (crossfade_mode) {
|
||||||
|
case CFM_MIX:
|
||||||
case CFM_CROSSFADE:
|
case CFM_CROSSFADE:
|
||||||
crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2;
|
crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2;
|
||||||
crossfade_rem = crossfade_amount;
|
crossfade_rem = crossfade_amount;
|
||||||
|
@ -354,6 +367,15 @@ int crossfade(short *buf, const short *buf2, int length)
|
||||||
|
|
||||||
size = MIN(length, crossfade_rem);
|
size = MIN(length, crossfade_rem);
|
||||||
switch (crossfade_mode) {
|
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:
|
case CFM_CROSSFADE:
|
||||||
val1 = (crossfade_rem<<10)/crossfade_amount;
|
val1 = (crossfade_rem<<10)/crossfade_amount;
|
||||||
val2 = ((crossfade_amount-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 ;
|
break ;
|
||||||
|
|
||||||
|
/* Join two streams. */
|
||||||
case CFM_FLUSH:
|
case CFM_FLUSH:
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
buf[i] = buf2[i];
|
buf[i] = buf2[i];
|
||||||
|
|
|
@ -36,7 +36,7 @@ void pcmbuf_set_watermark(int numbytes, void (*callback)(int bytes_left));
|
||||||
void pcmbuf_set_boost_mode(bool state);
|
void pcmbuf_set_boost_mode(bool state);
|
||||||
bool pcmbuf_is_lowdata(void);
|
bool pcmbuf_is_lowdata(void);
|
||||||
void pcmbuf_flush_audio(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));
|
void pcmbuf_add_event(void (*event_handler)(void));
|
||||||
unsigned int pcmbuf_get_latency(void);
|
unsigned int pcmbuf_get_latency(void);
|
||||||
bool pcmbuf_insert_buffer(char *buf, long length);
|
bool pcmbuf_insert_buffer(char *buf, long length);
|
||||||
|
|
|
@ -1175,7 +1175,8 @@ void audio_update_trackinfo(void)
|
||||||
cur_ti->start_pos = 0;
|
cur_ti->start_pos = 0;
|
||||||
ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
|
ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
|
||||||
if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) {
|
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();
|
codec_track_changed();
|
||||||
} else {
|
} else {
|
||||||
pcmbuf_add_event(codec_track_changed);
|
pcmbuf_add_event(codec_track_changed);
|
||||||
|
@ -1393,7 +1394,7 @@ void audio_thread(void)
|
||||||
ci.stop_codec = true;
|
ci.stop_codec = true;
|
||||||
ci.reload_codec = false;
|
ci.reload_codec = false;
|
||||||
ci.seek_time = 0;
|
ci.seek_time = 0;
|
||||||
pcmbuf_crossfade_init();
|
pcmbuf_crossfade_init(CROSSFADE_MODE_CROSSFADE);
|
||||||
while (codec_loaded)
|
while (codec_loaded)
|
||||||
yield();
|
yield();
|
||||||
audio_play_start((int)ev.data);
|
audio_play_start((int)ev.data);
|
||||||
|
@ -1771,19 +1772,22 @@ void audio_set_buffer_margin(int setting)
|
||||||
set_filebuf_watermark(buffer_margin);
|
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;
|
long size;
|
||||||
bool was_playing = playing;
|
bool was_playing = playing;
|
||||||
int offset = 0;
|
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 */
|
/* Store the track resume position */
|
||||||
if (playing)
|
if (playing)
|
||||||
offset = cur_ti->id3.offset;
|
offset = cur_ti->id3.offset;
|
||||||
|
|
||||||
/* Multiply by two to get the real value (0s, 2s, 4s, ...) */
|
if (type == CROSSFADE_MODE_OFF)
|
||||||
seconds *= 2;
|
seconds = 0;
|
||||||
|
|
||||||
/* Buffer has to be at least 2s long. */
|
/* Buffer has to be at least 2s long. */
|
||||||
seconds += 2;
|
seconds += 2;
|
||||||
logf("buf len: %d", seconds);
|
logf("buf len: %d", seconds);
|
||||||
|
|
|
@ -397,7 +397,7 @@ static const struct bit_entry hd_bits[] =
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_HWCODEC == MASNONE
|
#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
|
#endif
|
||||||
|
|
||||||
#if CONFIG_BACKLIGHT == BL_IRIVER
|
#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(next_folder), false, "move to next folder", off_on },
|
||||||
{1, S_O(runtimedb), false, "gather runtime data", 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 */
|
/* new stuff to be added at the end */
|
||||||
|
|
||||||
/* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
|
/* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
|
||||||
|
@ -851,7 +855,7 @@ void settings_apply(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_HWCODEC == MASNONE
|
#if CONFIG_HWCODEC == MASNONE
|
||||||
audio_set_crossfade_amount(global_settings.crossfade);
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SPDIF_POWER
|
#ifdef HAVE_SPDIF_POWER
|
||||||
|
|
|
@ -106,6 +106,10 @@
|
||||||
#define TRIG_DURATION_COUNT 13
|
#define TRIG_DURATION_COUNT 13
|
||||||
extern char *trig_durations[TRIG_DURATION_COUNT];
|
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,
|
/* 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.
|
or a mean a string ID if the pointer is in a certain range.
|
||||||
This helps to save space for menus and options. */
|
This helps to save space for menus and options. */
|
||||||
|
@ -151,6 +155,7 @@ struct user_settings
|
||||||
|
|
||||||
#if CONFIG_HWCODEC == MASNONE
|
#if CONFIG_HWCODEC == MASNONE
|
||||||
int crossfade;
|
int crossfade;
|
||||||
|
int crossfade_duration;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rec_quality; /* 0-7 */
|
int rec_quality; /* 0-7 */
|
||||||
|
|
|
@ -1131,6 +1131,22 @@ static bool crossfade(void)
|
||||||
{
|
{
|
||||||
static const struct opt_items names[] = {
|
static const struct opt_items names[] = {
|
||||||
{ STR(LANG_OFF) },
|
{ 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) },
|
{ "2s", TALK_ID(2, UNIT_SEC) },
|
||||||
{ "4s", TALK_ID(4, UNIT_SEC) },
|
{ "4s", TALK_ID(4, UNIT_SEC) },
|
||||||
{ "6s", TALK_ID(6, UNIT_SEC) },
|
{ "6s", TALK_ID(6, UNIT_SEC) },
|
||||||
|
@ -1140,13 +1156,12 @@ static bool crossfade(void)
|
||||||
{ "14s", TALK_ID(14, UNIT_SEC) },
|
{ "14s", TALK_ID(14, UNIT_SEC) },
|
||||||
};
|
};
|
||||||
bool ret;
|
bool ret;
|
||||||
ret=set_option( str(LANG_CROSSFADE), &global_settings.crossfade,
|
ret=set_option( str(LANG_CROSSFADE_DURATION),
|
||||||
INT, names, 8, NULL);
|
&global_settings.crossfade_duration, INT, names, 8, NULL);
|
||||||
audio_set_crossfade_amount(global_settings.crossfade);
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool next_folder(void)
|
static bool next_folder(void)
|
||||||
|
@ -1187,6 +1202,7 @@ static bool playback_settings_menu(void)
|
||||||
{ ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
|
{ ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
|
||||||
#if CONFIG_HWCODEC == MASNONE
|
#if CONFIG_HWCODEC == MASNONE
|
||||||
{ ID2P(LANG_CROSSFADE), crossfade },
|
{ ID2P(LANG_CROSSFADE), crossfade },
|
||||||
|
{ ID2P(LANG_CROSSFADE_DURATION), crossfade_duration },
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SPDIF_POWER
|
#ifdef HAVE_SPDIF_POWER
|
||||||
{ ID2P(LANG_SPDIF_ENABLE), spdif },
|
{ ID2P(LANG_SPDIF_ENABLE), spdif },
|
||||||
|
|
|
@ -71,7 +71,7 @@ struct mp3entry* audio_current_track(void);
|
||||||
struct mp3entry* audio_next_track(void);
|
struct mp3entry* audio_next_track(void);
|
||||||
bool audio_has_changed_track(void);
|
bool audio_has_changed_track(void);
|
||||||
void audio_get_debugdata(struct audio_debug *dbgdata);
|
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);
|
void audio_set_buffer_margin(int seconds);
|
||||||
unsigned int audio_error(void);
|
unsigned int audio_error(void);
|
||||||
void audio_error_clear(void);
|
void audio_error_clear(void);
|
||||||
|
|
|
@ -286,7 +286,7 @@ void DMA0(void)
|
||||||
/* Stop on error */
|
/* Stop on error */
|
||||||
if(res & 0x70)
|
if(res & 0x70)
|
||||||
{
|
{
|
||||||
dma_stop();
|
pcm_play_stop();
|
||||||
logf("DMA Error:0x%04x", res);
|
logf("DMA Error:0x%04x", res);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -302,7 +302,7 @@ void DMA0(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Finished playing */
|
/* Finished playing */
|
||||||
dma_stop();
|
pcm_play_stop();
|
||||||
logf("DMA No Data:0x%04x", res);
|
logf("DMA No Data:0x%04x", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue