iRiver: New crossfader with more configuration capability. Might still
have small bugs, but those will be fixed as soon as possible. Config block version bumped; please SAVE YOUR SETTINGS. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7765 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
ce1312e383
commit
e7461b3609
8 changed files with 396 additions and 108 deletions
|
@ -3168,9 +3168,9 @@ voice: ""
|
||||||
new:
|
new:
|
||||||
|
|
||||||
id: LANG_CROSSFADE_DURATION
|
id: LANG_CROSSFADE_DURATION
|
||||||
desc: in playback settings
|
desc: DEPRECATED
|
||||||
eng: "Crossfade duration"
|
eng: ""
|
||||||
voice: "Crossfade duration"
|
voice: ""
|
||||||
new:
|
new:
|
||||||
|
|
||||||
id: LANG_MIX
|
id: LANG_MIX
|
||||||
|
@ -3316,3 +3316,39 @@ desc: when booting up and rebuilding the cache
|
||||||
eng: "Scanning disk..."
|
eng: "Scanning disk..."
|
||||||
voice: ""
|
voice: ""
|
||||||
new:
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_ENABLE
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Enable crossfade"
|
||||||
|
voice: "Enable crossfade"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_IN_DELAY
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade in delay"
|
||||||
|
voice: "Fade in delay"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_DELAY
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out delay"
|
||||||
|
voice: "Fade out delay"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_IN_DURATION
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade in duration"
|
||||||
|
voice: "Fade in duration"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_DURATION
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out duration"
|
||||||
|
voice: "Fade out duration"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_MODE
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out mode"
|
||||||
|
voice: "Fade out mode"
|
||||||
|
new:
|
||||||
|
|
|
@ -3144,10 +3144,10 @@ voice: "Crossfade"
|
||||||
new: "Ristivaihto"
|
new: "Ristivaihto"
|
||||||
|
|
||||||
id: LANG_CROSSFADE_DURATION
|
id: LANG_CROSSFADE_DURATION
|
||||||
desc: in playback settings
|
desc: DEPRECATED
|
||||||
eng: "Crossfade duration"
|
eng: ""
|
||||||
voice: "Ristivaihdon kesto"
|
voice: ""
|
||||||
new: "Ristivaihdon kesto"
|
new: ""
|
||||||
|
|
||||||
id: LANG_SHUFFLE_PLAYLIST
|
id: LANG_SHUFFLE_PLAYLIST
|
||||||
desc: in playlist menu, reshuffles the order in which songs are played
|
desc: in playlist menu, reshuffles the order in which songs are played
|
||||||
|
@ -3347,3 +3347,39 @@ desc: when booting up and rebuilding the cache
|
||||||
eng: "Scanning disk..."
|
eng: "Scanning disk..."
|
||||||
voice: ""
|
voice: ""
|
||||||
new: "Ladataan hakemistopuu..."
|
new: "Ladataan hakemistopuu..."
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_ENABLE
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Enable crossfade"
|
||||||
|
voice: "Aktivoi ristivaihto"
|
||||||
|
new: "Aktivoi ristivaihto"
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_IN_DELAY
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade in delay"
|
||||||
|
voice: "Sisäänhäivytyksen viive"
|
||||||
|
new: "Sisäänhäivytyksen viive"
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_DELAY
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out delay"
|
||||||
|
voice: "Poishäivytyksen viive"
|
||||||
|
new: "Poishäivytyksen viive"
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_IN_DURATION
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade in duration"
|
||||||
|
voice: "Sisäänhäivytyksen kesto"
|
||||||
|
new: "Sisäänhäivytyksen kesto"
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_DURATION
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out duration"
|
||||||
|
voice: "Poishäivytyksen kesto"
|
||||||
|
new: "Poishäivytyksen kesto"
|
||||||
|
|
||||||
|
id: LANG_CROSSFADE_FADE_OUT_MODE
|
||||||
|
desc: in crossfade settings menu
|
||||||
|
eng: "Fade out mode"
|
||||||
|
voice: "Poishäivytyksen tyyli"
|
||||||
|
new: "Poishäivytyksen tyyli"
|
||||||
|
|
216
apps/pcmbuf.c
216
apps/pcmbuf.c
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
#define CHUNK_SIZE PCMBUF_GUARD
|
#define CHUNK_SIZE PCMBUF_GUARD
|
||||||
/* Must be a power of 2 */
|
/* Must be a power of 2 */
|
||||||
#define NUM_PCM_BUFFERS 64
|
#define NUM_PCM_BUFFERS 128
|
||||||
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
|
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
|
||||||
#define PCMBUF_WATERMARK (CHUNK_SIZE * 6)
|
#define PCMBUF_WATERMARK (CHUNK_SIZE * 6)
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ static bool crossfade_enabled;
|
||||||
static bool crossfade_active;
|
static bool crossfade_active;
|
||||||
static bool crossfade_init;
|
static bool crossfade_init;
|
||||||
static int crossfade_pos;
|
static int crossfade_pos;
|
||||||
static int crossfade_amount;
|
|
||||||
static int crossfade_rem;
|
static int crossfade_rem;
|
||||||
|
|
||||||
/* Crossfade modes. If CFM_CROSSFADE is selected, normal
|
/* Crossfade modes. If CFM_CROSSFADE is selected, normal
|
||||||
|
@ -71,6 +70,9 @@ enum {
|
||||||
CFM_FLUSH
|
CFM_FLUSH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int crossfade_fade_in_amount;
|
||||||
|
static int crossfade_fade_in_rem;
|
||||||
|
|
||||||
/* Structure we can use to queue pcm chunks in memory to be played
|
/* Structure we can use to queue pcm chunks in memory to be played
|
||||||
* by the driver code. */
|
* by the driver code. */
|
||||||
struct pcmbufdesc
|
struct pcmbufdesc
|
||||||
|
@ -225,7 +227,7 @@ bool pcmbuf_is_lowdata(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pcmbuf_crossfade_init(int type)
|
bool pcmbuf_crossfade_init(void)
|
||||||
{
|
{
|
||||||
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) {
|
||||||
|
@ -235,17 +237,8 @@ bool pcmbuf_crossfade_init(int type)
|
||||||
logf("pcmbuf_crossfade_init");
|
logf("pcmbuf_crossfade_init");
|
||||||
pcmbuf_boost(true);
|
pcmbuf_boost(true);
|
||||||
|
|
||||||
switch (type) {
|
crossfade_mode = global_settings.crossfade_fade_out_mixmode
|
||||||
case CROSSFADE_MODE_CROSSFADE:
|
? CFM_MIX : CFM_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;
|
||||||
|
@ -308,6 +301,9 @@ void pcmbuf_play_start(void)
|
||||||
pcm_play_data(pcmbuf_callback);
|
pcm_play_data(pcmbuf_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit samples waiting to the pcm buffer.
|
||||||
|
*/
|
||||||
void pcmbuf_flush_fillpos(void)
|
void pcmbuf_flush_fillpos(void)
|
||||||
{
|
{
|
||||||
int copy_n;
|
int copy_n;
|
||||||
|
@ -335,9 +331,59 @@ void pcmbuf_flush_fillpos(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely process the crossfade fade out effect with current pcm buffer.
|
||||||
|
*/
|
||||||
|
static void crossfade_process_buffer(
|
||||||
|
int fade_in_delay, int fade_out_delay, int fade_out_rem)
|
||||||
|
{
|
||||||
|
int amount;
|
||||||
|
int pos;
|
||||||
|
short *buf;
|
||||||
|
|
||||||
|
/* Fade out the entire current buffer according to settings. */
|
||||||
|
amount = fade_out_rem;
|
||||||
|
pos = crossfade_pos + fade_out_delay*2;
|
||||||
|
|
||||||
|
while (fade_out_rem > 0 && crossfade_mode == CFM_CROSSFADE)
|
||||||
|
{
|
||||||
|
int blocksize = MIN(8192, fade_out_rem);
|
||||||
|
int factor = (fade_out_rem<<8)/amount;
|
||||||
|
|
||||||
|
/* Prevent pcmbuffer from wrapping. */
|
||||||
|
if (pos >= pcmbuf_size)
|
||||||
|
pos -= pcmbuf_size;
|
||||||
|
blocksize = MIN(pcmbuf_size - pos, blocksize);
|
||||||
|
buf = (short *)&audiobuffer[pos];
|
||||||
|
|
||||||
|
fade_out_rem -= blocksize;
|
||||||
|
pos += blocksize * 2;
|
||||||
|
while (blocksize > 0)
|
||||||
|
{
|
||||||
|
*buf = (*buf * factor) >> 8;
|
||||||
|
*buf++;
|
||||||
|
blocksize--;
|
||||||
|
}
|
||||||
|
//yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And finally set the mixing position where we should start fading in. */
|
||||||
|
crossfade_rem -= fade_in_delay;
|
||||||
|
crossfade_pos += fade_in_delay*2;
|
||||||
|
if (crossfade_pos >= pcmbuf_size)
|
||||||
|
crossfade_pos -= pcmbuf_size;
|
||||||
|
logf("process done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes crossfader, calculates all necessary parameters and
|
||||||
|
* performs fade-out with the pcm buffer.
|
||||||
|
*/
|
||||||
static void crossfade_start(void)
|
static void crossfade_start(void)
|
||||||
{
|
{
|
||||||
int bytesleft = pcmbuf_unplayed_bytes;
|
int bytesleft = pcmbuf_unplayed_bytes;
|
||||||
|
int fade_out_rem = 0, fade_out_delay = 0;
|
||||||
|
int fade_in_delay = 0;
|
||||||
|
|
||||||
crossfade_init = 0;
|
crossfade_init = 0;
|
||||||
if (bytesleft < CHUNK_SIZE * 4) {
|
if (bytesleft < CHUNK_SIZE * 4) {
|
||||||
|
@ -356,44 +402,125 @@ static void crossfade_start(void)
|
||||||
switch (crossfade_mode) {
|
switch (crossfade_mode) {
|
||||||
case CFM_MIX:
|
case CFM_MIX:
|
||||||
case CFM_CROSSFADE:
|
case CFM_CROSSFADE:
|
||||||
crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2;
|
/* Initialize the crossfade buffer size. */
|
||||||
crossfade_rem = crossfade_amount;
|
crossfade_rem = (bytesleft - (CHUNK_SIZE * 2))/2;
|
||||||
|
|
||||||
|
/* Get fade out delay from settings. */
|
||||||
|
fade_out_delay = NATIVE_FREQUENCY
|
||||||
|
* global_settings.crossfade_fade_out_delay * 2;
|
||||||
|
|
||||||
|
/* Get fade out duration from settings. */
|
||||||
|
fade_out_rem = NATIVE_FREQUENCY
|
||||||
|
* global_settings.crossfade_fade_out_duration * 2;
|
||||||
|
|
||||||
|
/* Truncate fade out duration if necessary. */
|
||||||
|
if (fade_out_rem > crossfade_rem)
|
||||||
|
fade_out_rem = crossfade_rem;
|
||||||
|
|
||||||
|
/* We want only to modify the last part of the buffer. */
|
||||||
|
if (crossfade_rem > fade_out_rem + fade_out_delay)
|
||||||
|
crossfade_rem = fade_out_rem + fade_out_delay;
|
||||||
|
|
||||||
|
/* Get also fade in duration and delays from settings. */
|
||||||
|
crossfade_fade_in_rem = NATIVE_FREQUENCY
|
||||||
|
* global_settings.crossfade_fade_in_duration * 2;
|
||||||
|
crossfade_fade_in_amount = crossfade_fade_in_rem;
|
||||||
|
|
||||||
|
/* We should avoid to divide by zero. */
|
||||||
|
if (crossfade_fade_in_amount == 0)
|
||||||
|
crossfade_fade_in_amount = 1;
|
||||||
|
|
||||||
|
fade_in_delay = NATIVE_FREQUENCY
|
||||||
|
* global_settings.crossfade_fade_in_delay * 2;
|
||||||
|
|
||||||
|
/* Decrease the fade out delay if necessary. */
|
||||||
|
fade_out_delay += MIN(crossfade_rem -
|
||||||
|
fade_out_rem -
|
||||||
|
fade_out_delay, 0);
|
||||||
|
if (fade_out_delay < 0)
|
||||||
|
fade_out_delay = 0;
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case CFM_FLUSH:
|
case CFM_FLUSH:
|
||||||
crossfade_amount = bytesleft /2;
|
crossfade_rem = bytesleft /2;
|
||||||
crossfade_rem = crossfade_amount;
|
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
|
|
||||||
crossfade_pos -= crossfade_amount*2;
|
crossfade_pos -= crossfade_rem*2;
|
||||||
if (crossfade_pos < 0)
|
if (crossfade_pos < 0)
|
||||||
crossfade_pos += pcmbuf_size;
|
crossfade_pos += pcmbuf_size;
|
||||||
|
|
||||||
|
if (crossfade_mode != CFM_FLUSH) {
|
||||||
|
/* Process the fade out part of the crossfade. */
|
||||||
|
crossfade_process_buffer(fade_in_delay, fade_out_delay, fade_out_rem);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades in samples passed to the function and inserts them
|
||||||
|
* to the pcm buffer.
|
||||||
|
*/
|
||||||
|
static void fade_insert(const short *inbuf, int length)
|
||||||
|
{
|
||||||
|
int copy_n;
|
||||||
|
int factor;
|
||||||
|
int i, samples;
|
||||||
|
short *buf;
|
||||||
|
|
||||||
|
factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)
|
||||||
|
<<8)/crossfade_fade_in_amount;
|
||||||
|
|
||||||
|
while (audiobuffer_free < length + audiobuffer_fillpos
|
||||||
|
+ CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
pcmbuf_boost(false);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos -
|
||||||
|
audiobuffer_fillpos);
|
||||||
|
copy_n = MIN(CHUNK_SIZE - audiobuffer_fillpos, copy_n);
|
||||||
|
|
||||||
|
buf = (short *)&audiobuffer[audiobuffer_pos+audiobuffer_fillpos];
|
||||||
|
samples = copy_n / 2;
|
||||||
|
for (i = 0; i < samples; i++)
|
||||||
|
buf[i] = (inbuf[i] * factor) >> 8;
|
||||||
|
|
||||||
|
inbuf += samples;
|
||||||
|
audiobuffer_fillpos += copy_n;
|
||||||
|
length -= copy_n;
|
||||||
|
|
||||||
|
/* Pre-buffer to meet CHUNK_SIZE requirement */
|
||||||
|
if (audiobuffer_fillpos < CHUNK_SIZE && length == 0) {
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcmbuf_flush_fillpos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades in buf2 and mixes it with buf.
|
||||||
|
*/
|
||||||
static __inline
|
static __inline
|
||||||
int crossfade(short *buf, const short *buf2, int length)
|
int crossfade(short *buf, const short *buf2, int length)
|
||||||
{
|
{
|
||||||
int size, i;
|
int size, i;
|
||||||
int val1, val2;
|
int size_insert = 0;
|
||||||
|
int factor;
|
||||||
|
|
||||||
size = MIN(length, crossfade_rem);
|
size = MAX(0, MIN(length, crossfade_rem));
|
||||||
switch (crossfade_mode) {
|
switch (crossfade_mode) {
|
||||||
/* Mix two streams. */
|
/* Fade in the current stream and mix it. */
|
||||||
case CFM_MIX:
|
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;
|
factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)
|
||||||
val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
|
<<8)/crossfade_fade_in_amount;
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10;
|
buf[i] = MIN(MAX(buf[i] + ((buf2[i] * factor) >> 8), -32768), 32767);
|
||||||
}
|
}
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
|
@ -405,12 +532,20 @@ int crossfade(short *buf, const short *buf2, int length)
|
||||||
//memcpy((char *)buf, (char *)buf2, size*2);
|
//memcpy((char *)buf, (char *)buf2, size*2);
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crossfade_fade_in_rem = MAX(0, crossfade_fade_in_rem - size);
|
||||||
crossfade_rem -= size;
|
crossfade_rem -= size;
|
||||||
if (crossfade_rem <= 0)
|
if (crossfade_rem <= 0)
|
||||||
crossfade_active = false;
|
{
|
||||||
|
size_insert = MAX(0, MIN(crossfade_fade_in_rem, length - size));
|
||||||
return size;
|
fade_insert(&buf2[size], size_insert*2);
|
||||||
|
crossfade_fade_in_rem -= size_insert;
|
||||||
|
|
||||||
|
if (crossfade_fade_in_rem <= 0)
|
||||||
|
crossfade_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size + size_insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool prepare_insert(long length)
|
static bool prepare_insert(long length)
|
||||||
|
@ -486,13 +621,12 @@ void pcmbuf_flush_buffer(long length)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
|
pcmbuf_flush_fillpos();
|
||||||
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
|
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
|
||||||
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
||||||
audiobuffer_fillpos = copy_n;
|
audiobuffer_fillpos = copy_n;
|
||||||
buf += copy_n;
|
buf += copy_n;
|
||||||
length -= copy_n;
|
length -= copy_n;
|
||||||
if (length > 0)
|
|
||||||
pcmbuf_flush_fillpos();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,13 +671,12 @@ bool pcmbuf_insert_buffer(char *buf, long length)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
|
pcmbuf_flush_fillpos();
|
||||||
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
|
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
|
||||||
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
||||||
audiobuffer_fillpos = copy_n;
|
audiobuffer_fillpos = copy_n;
|
||||||
buf += copy_n;
|
buf += copy_n;
|
||||||
length -= copy_n;
|
length -= copy_n;
|
||||||
if (length > 0)
|
|
||||||
pcmbuf_flush_fillpos();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,6 +807,9 @@ void pcmbuf_crossfade_enable(bool on_off)
|
||||||
|
|
||||||
bool pcmbuf_is_crossfade_enabled(void)
|
bool pcmbuf_is_crossfade_enabled(void)
|
||||||
{
|
{
|
||||||
|
if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE)
|
||||||
|
return global_settings.playlist_shuffle;
|
||||||
|
|
||||||
return crossfade_enabled;
|
return crossfade_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ 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);
|
||||||
void pcmbuf_play_start(void);
|
void pcmbuf_play_start(void);
|
||||||
bool pcmbuf_crossfade_init(int type);
|
bool pcmbuf_crossfade_init(void);
|
||||||
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);
|
||||||
|
|
|
@ -1441,8 +1441,7 @@ 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(new_track ? CROSSFADE_MODE_CROSSFADE
|
pcmbuf_crossfade_init();
|
||||||
: global_settings.crossfade);
|
|
||||||
codec_track_changed();
|
codec_track_changed();
|
||||||
} else {
|
} else {
|
||||||
pcmbuf_add_event(codec_track_changed);
|
pcmbuf_add_event(codec_track_changed);
|
||||||
|
@ -1706,7 +1705,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(CROSSFADE_MODE_CROSSFADE);
|
pcmbuf_crossfade_init();
|
||||||
while (audio_codec_loaded)
|
while (audio_codec_loaded)
|
||||||
yield();
|
yield();
|
||||||
audio_play_start((int)ev.data);
|
audio_play_start((int)ev.data);
|
||||||
|
@ -2227,13 +2226,12 @@ void audio_set_buffer_margin(int setting)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set crossfade & PCM buffer length. */
|
/* Set crossfade & PCM buffer length. */
|
||||||
void audio_set_crossfade(int type)
|
void audio_set_crossfade(int enable)
|
||||||
{
|
{
|
||||||
long size;
|
long size;
|
||||||
bool was_playing = playing;
|
bool was_playing = playing;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
static const int lookup[] = {1, 2, 4, 6, 8, 10, 12, 14};
|
int seconds = 1;
|
||||||
int seconds = lookup[global_settings.crossfade_duration];
|
|
||||||
|
|
||||||
if (!filebuf)
|
if (!filebuf)
|
||||||
return; /* Audio buffers not yet set up */
|
return; /* Audio buffers not yet set up */
|
||||||
|
@ -2242,8 +2240,11 @@ void audio_set_crossfade(int type)
|
||||||
if (playing)
|
if (playing)
|
||||||
offset = cur_ti->id3.offset;
|
offset = cur_ti->id3.offset;
|
||||||
|
|
||||||
if (type == CROSSFADE_MODE_OFF)
|
if (enable)
|
||||||
seconds = 1;
|
{
|
||||||
|
seconds = global_settings.crossfade_fade_out_delay
|
||||||
|
+ global_settings.crossfade_fade_out_duration;
|
||||||
|
}
|
||||||
|
|
||||||
/* Buffer has to be at least 2s long. */
|
/* Buffer has to be at least 2s long. */
|
||||||
seconds += 2;
|
seconds += 2;
|
||||||
|
@ -2259,7 +2260,7 @@ void audio_set_crossfade(int type)
|
||||||
if (was_playing)
|
if (was_playing)
|
||||||
splash(0, true, str(LANG_RESTARTING_PLAYBACK));
|
splash(0, true, str(LANG_RESTARTING_PLAYBACK));
|
||||||
pcmbuf_init(size);
|
pcmbuf_init(size);
|
||||||
pcmbuf_crossfade_enable(type != CROSSFADE_MODE_OFF);
|
pcmbuf_crossfade_enable(enable);
|
||||||
reset_buffer();
|
reset_buffer();
|
||||||
logf("abuf:%dB", pcmbuf_get_bufsize());
|
logf("abuf:%dB", pcmbuf_get_bufsize());
|
||||||
logf("fbuf:%dB", filebuflen);
|
logf("fbuf:%dB", filebuflen);
|
||||||
|
|
|
@ -85,7 +85,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CONFIG_BLOCK_VERSION 28
|
#define CONFIG_BLOCK_VERSION 29
|
||||||
#define CONFIG_BLOCK_SIZE 512
|
#define CONFIG_BLOCK_SIZE 512
|
||||||
#define RTC_BLOCK_SIZE 44
|
#define RTC_BLOCK_SIZE 44
|
||||||
|
|
||||||
|
@ -417,10 +417,6 @@ static const struct bit_entry hd_bits[] =
|
||||||
{4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
|
{4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
|
||||||
{3, S_O(crossfade_duration), 0, "crossfade duration", "1s,2s,4s,6s,8s,10s,12s,14s"},
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_BACKLIGHT == BL_IRIVER
|
#if CONFIG_BACKLIGHT == BL_IRIVER
|
||||||
/* backlight fading */
|
/* backlight fading */
|
||||||
{2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
|
{2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
|
||||||
|
@ -436,13 +432,18 @@ static const struct bit_entry hd_bits[] =
|
||||||
{1, S_O(runtimedb), false, "gather runtime data", off_on },
|
{1, S_O(runtimedb), false, "gather runtime data", off_on },
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
{2, S_O(crossfade), 0, "crossfade type", "off,crossfade,mix"},
|
|
||||||
{1, S_O(replaygain), false, "replaygain", off_on },
|
{1, S_O(replaygain), false, "replaygain", off_on },
|
||||||
{2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
|
{2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
|
||||||
"track,album,track shuffle" },
|
"track,album,track shuffle" },
|
||||||
{1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
|
{1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
|
||||||
{8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
|
{8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
|
||||||
{2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
|
{2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
|
||||||
|
{2, S_O(crossfade), 0, "crossfade", "off,shuffle,always"},
|
||||||
|
{3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
|
||||||
|
{3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
|
||||||
|
{4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
|
||||||
|
{4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
|
||||||
|
{1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_DIRCACHE
|
#ifdef HAVE_DIRCACHE
|
||||||
{1, S_O(dircache), false, "dircache", off_on },
|
{1, S_O(dircache), false, "dircache", off_on },
|
||||||
|
|
|
@ -109,9 +109,8 @@
|
||||||
#define TRIG_DURATION_COUNT 13
|
#define TRIG_DURATION_COUNT 13
|
||||||
extern const char * const trig_durations[TRIG_DURATION_COUNT];
|
extern const char * const trig_durations[TRIG_DURATION_COUNT];
|
||||||
|
|
||||||
#define CROSSFADE_MODE_OFF 0
|
#define CROSSFADE_ENABLE_SHUFFLE 1
|
||||||
#define CROSSFADE_MODE_CROSSFADE 1
|
#define CROSSFADE_ENABLE_ALWAYS 2
|
||||||
#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.
|
||||||
|
@ -157,8 +156,12 @@ struct user_settings
|
||||||
bool superbass; /* true/false */
|
bool superbass; /* true/false */
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
int crossfade;
|
int crossfade; /* Enable crossfade (0=off,1=shuffle,2=always) */
|
||||||
int crossfade_duration;
|
int crossfade_fade_in_delay; /* Fade in delay (0-15s) */
|
||||||
|
int crossfade_fade_out_delay; /* Fade out delay (0-15s) */
|
||||||
|
int crossfade_fade_in_duration; /* Fade in duration (0-15s) */
|
||||||
|
int crossfade_fade_out_duration; /* Fade out duration (0-15s) */
|
||||||
|
int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rec_quality; /* 0-7 */
|
int rec_quality; /* 0-7 */
|
||||||
|
|
|
@ -1110,44 +1110,6 @@ static bool id3_order(void)
|
||||||
mpeg_id3_options);
|
mpeg_id3_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
|
||||||
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) },
|
|
||||||
{ "8s", TALK_ID(8, UNIT_SEC) },
|
|
||||||
{ "10s", TALK_ID(10, UNIT_SEC) },
|
|
||||||
{ "12s", TALK_ID(12, UNIT_SEC) },
|
|
||||||
{ "14s", TALK_ID(14, UNIT_SEC) },
|
|
||||||
};
|
|
||||||
bool ret;
|
|
||||||
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)
|
static bool next_folder(void)
|
||||||
{
|
{
|
||||||
return set_bool( str(LANG_NEXT_FOLDER), &global_settings.next_folder );
|
return set_bool( str(LANG_NEXT_FOLDER), &global_settings.next_folder );
|
||||||
|
@ -1239,6 +1201,120 @@ static bool replaygain_settings_menu(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool crossfade(void)
|
||||||
|
{
|
||||||
|
static const struct opt_items names[] = {
|
||||||
|
{ STR(LANG_OFF) },
|
||||||
|
{ STR(LANG_SHUFFLE) },
|
||||||
|
{ STR(LANG_ALWAYS) },
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_ENABLE),
|
||||||
|
&global_settings.crossfade, INT, names, 3, NULL);
|
||||||
|
|
||||||
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct opt_items crossfade_time[] = {
|
||||||
|
{ "0s", TALK_ID(0, UNIT_SEC) },
|
||||||
|
{ "1s", TALK_ID(1, UNIT_SEC) },
|
||||||
|
{ "2s", TALK_ID(2, UNIT_SEC) },
|
||||||
|
{ "3s", TALK_ID(3, UNIT_SEC) },
|
||||||
|
{ "4s", TALK_ID(4, UNIT_SEC) },
|
||||||
|
{ "5s", TALK_ID(5, UNIT_SEC) },
|
||||||
|
{ "6s", TALK_ID(6, UNIT_SEC) },
|
||||||
|
{ "7s", TALK_ID(7, UNIT_SEC) },
|
||||||
|
{ "8s", TALK_ID(8, UNIT_SEC) },
|
||||||
|
{ "9s", TALK_ID(9, UNIT_SEC) },
|
||||||
|
{ "10s", TALK_ID(10, UNIT_SEC) },
|
||||||
|
{ "11s", TALK_ID(11, UNIT_SEC) },
|
||||||
|
{ "12s", TALK_ID(12, UNIT_SEC) },
|
||||||
|
{ "13s", TALK_ID(13, UNIT_SEC) },
|
||||||
|
{ "14s", TALK_ID(14, UNIT_SEC) },
|
||||||
|
{ "15s", TALK_ID(15, UNIT_SEC) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool crossfade_fade_in_delay(void)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_FADE_IN_DELAY),
|
||||||
|
&global_settings.crossfade_fade_in_delay, INT, crossfade_time, 8, NULL);
|
||||||
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool crossfade_fade_out_delay(void)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_FADE_OUT_DELAY),
|
||||||
|
&global_settings.crossfade_fade_out_delay, INT, crossfade_time, 8, NULL);
|
||||||
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool crossfade_fade_in_duration(void)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_FADE_IN_DURATION),
|
||||||
|
&global_settings.crossfade_fade_in_duration, INT, crossfade_time, 16, NULL);
|
||||||
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool crossfade_fade_out_duration(void)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_FADE_OUT_DURATION),
|
||||||
|
&global_settings.crossfade_fade_out_duration, INT, crossfade_time, 16, NULL);
|
||||||
|
audio_set_crossfade(global_settings.crossfade);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool crossfade_fade_out_mixmode(void)
|
||||||
|
{
|
||||||
|
static const struct opt_items names[] = {
|
||||||
|
{ STR(LANG_CROSSFADE) },
|
||||||
|
{ STR(LANG_MIX) },
|
||||||
|
};
|
||||||
|
bool ret;
|
||||||
|
ret=set_option( str(LANG_CROSSFADE_FADE_OUT_MODE),
|
||||||
|
&global_settings.crossfade_fade_out_mixmode, INT, names, 2, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu to configure the crossfade settings.
|
||||||
|
*/
|
||||||
|
static bool crossfade_settings_menu(void)
|
||||||
|
{
|
||||||
|
int m;
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
static const struct menu_item items[] = {
|
||||||
|
{ ID2P(LANG_CROSSFADE_ENABLE), crossfade },
|
||||||
|
{ ID2P(LANG_CROSSFADE_FADE_IN_DELAY), crossfade_fade_in_delay },
|
||||||
|
{ ID2P(LANG_CROSSFADE_FADE_IN_DURATION), crossfade_fade_in_duration },
|
||||||
|
{ ID2P(LANG_CROSSFADE_FADE_OUT_DELAY), crossfade_fade_out_delay },
|
||||||
|
{ ID2P(LANG_CROSSFADE_FADE_OUT_DURATION), crossfade_fade_out_duration },
|
||||||
|
{ ID2P(LANG_CROSSFADE_FADE_OUT_MODE), crossfade_fade_out_mixmode },
|
||||||
|
};
|
||||||
|
|
||||||
|
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
result = menu_run(m);
|
||||||
|
menu_exit(m);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static bool beep(void)
|
static bool beep(void)
|
||||||
{
|
{
|
||||||
static const struct opt_items names[] = {
|
static const struct opt_items names[] = {
|
||||||
|
@ -1289,8 +1365,7 @@ static bool playback_settings_menu(void)
|
||||||
{ ID2P(LANG_MP3BUFFER_MARGIN), buffer_margin },
|
{ ID2P(LANG_MP3BUFFER_MARGIN), buffer_margin },
|
||||||
{ ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
|
{ ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
{ ID2P(LANG_CROSSFADE), crossfade },
|
{ ID2P(LANG_CROSSFADE), crossfade_settings_menu },
|
||||||
{ ID2P(LANG_CROSSFADE_DURATION), crossfade_duration },
|
|
||||||
{ ID2P(LANG_REPLAYGAIN), replaygain_settings_menu },
|
{ ID2P(LANG_REPLAYGAIN), replaygain_settings_menu },
|
||||||
{ ID2P(LANG_BEEP), beep },
|
{ ID2P(LANG_BEEP), beep },
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue