summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/lang/english.lang42
-rw-r--r--apps/lang/finnish.lang44
-rw-r--r--apps/pcmbuf.c216
-rw-r--r--apps/pcmbuf.h2
-rw-r--r--apps/playback.c19
-rw-r--r--apps/settings.c13
-rw-r--r--apps/settings.h13
-rw-r--r--apps/settings_menu.c155
8 files changed, 396 insertions, 108 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 7906ed39c3..9d547173c7 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3168,9 +3168,9 @@ voice: ""
3168new: 3168new:
3169 3169
3170id: LANG_CROSSFADE_DURATION 3170id: LANG_CROSSFADE_DURATION
3171desc: in playback settings 3171desc: DEPRECATED
3172eng: "Crossfade duration" 3172eng: ""
3173voice: "Crossfade duration" 3173voice: ""
3174new: 3174new:
3175 3175
3176id: LANG_MIX 3176id: LANG_MIX
@@ -3316,3 +3316,39 @@ desc: when booting up and rebuilding the cache
3316eng: "Scanning disk..." 3316eng: "Scanning disk..."
3317voice: "" 3317voice: ""
3318new: 3318new:
3319
3320id: LANG_CROSSFADE_ENABLE
3321desc: in crossfade settings menu
3322eng: "Enable crossfade"
3323voice: "Enable crossfade"
3324new:
3325
3326id: LANG_CROSSFADE_FADE_IN_DELAY
3327desc: in crossfade settings menu
3328eng: "Fade in delay"
3329voice: "Fade in delay"
3330new:
3331
3332id: LANG_CROSSFADE_FADE_OUT_DELAY
3333desc: in crossfade settings menu
3334eng: "Fade out delay"
3335voice: "Fade out delay"
3336new:
3337
3338id: LANG_CROSSFADE_FADE_IN_DURATION
3339desc: in crossfade settings menu
3340eng: "Fade in duration"
3341voice: "Fade in duration"
3342new:
3343
3344id: LANG_CROSSFADE_FADE_OUT_DURATION
3345desc: in crossfade settings menu
3346eng: "Fade out duration"
3347voice: "Fade out duration"
3348new:
3349
3350id: LANG_CROSSFADE_FADE_OUT_MODE
3351desc: in crossfade settings menu
3352eng: "Fade out mode"
3353voice: "Fade out mode"
3354new:
diff --git a/apps/lang/finnish.lang b/apps/lang/finnish.lang
index 1e6a7eb52e..290d3316d4 100644
--- a/apps/lang/finnish.lang
+++ b/apps/lang/finnish.lang
@@ -3144,10 +3144,10 @@ voice: "Crossfade"
3144new: "Ristivaihto" 3144new: "Ristivaihto"
3145 3145
3146id: LANG_CROSSFADE_DURATION 3146id: LANG_CROSSFADE_DURATION
3147desc: in playback settings 3147desc: DEPRECATED
3148eng: "Crossfade duration" 3148eng: ""
3149voice: "Ristivaihdon kesto" 3149voice: ""
3150new: "Ristivaihdon kesto" 3150new: ""
3151 3151
3152id: LANG_SHUFFLE_PLAYLIST 3152id: LANG_SHUFFLE_PLAYLIST
3153desc: in playlist menu, reshuffles the order in which songs are played 3153desc: in playlist menu, reshuffles the order in which songs are played
@@ -3347,3 +3347,39 @@ desc: when booting up and rebuilding the cache
3347eng: "Scanning disk..." 3347eng: "Scanning disk..."
3348voice: "" 3348voice: ""
3349new: "Ladataan hakemistopuu..." 3349new: "Ladataan hakemistopuu..."
3350
3351id: LANG_CROSSFADE_ENABLE
3352desc: in crossfade settings menu
3353eng: "Enable crossfade"
3354voice: "Aktivoi ristivaihto"
3355new: "Aktivoi ristivaihto"
3356
3357id: LANG_CROSSFADE_FADE_IN_DELAY
3358desc: in crossfade settings menu
3359eng: "Fade in delay"
3360voice: "Sisäänhäivytyksen viive"
3361new: "Sisäänhäivytyksen viive"
3362
3363id: LANG_CROSSFADE_FADE_OUT_DELAY
3364desc: in crossfade settings menu
3365eng: "Fade out delay"
3366voice: "Poishäivytyksen viive"
3367new: "Poishäivytyksen viive"
3368
3369id: LANG_CROSSFADE_FADE_IN_DURATION
3370desc: in crossfade settings menu
3371eng: "Fade in duration"
3372voice: "Sisäänhäivytyksen kesto"
3373new: "Sisäänhäivytyksen kesto"
3374
3375id: LANG_CROSSFADE_FADE_OUT_DURATION
3376desc: in crossfade settings menu
3377eng: "Fade out duration"
3378voice: "Poishäivytyksen kesto"
3379new: "Poishäivytyksen kesto"
3380
3381id: LANG_CROSSFADE_FADE_OUT_MODE
3382desc: in crossfade settings menu
3383eng: "Fade out mode"
3384voice: "Poishäivytyksen tyyli"
3385new: "Poishäivytyksen tyyli"
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 8ab4ffaae1..6024756c74 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -38,7 +38,7 @@
38 38
39#define CHUNK_SIZE PCMBUF_GUARD 39#define CHUNK_SIZE PCMBUF_GUARD
40/* Must be a power of 2 */ 40/* Must be a power of 2 */
41#define NUM_PCM_BUFFERS 64 41#define NUM_PCM_BUFFERS 128
42#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1) 42#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
43#define PCMBUF_WATERMARK (CHUNK_SIZE * 6) 43#define PCMBUF_WATERMARK (CHUNK_SIZE * 6)
44 44
@@ -58,7 +58,6 @@ static bool crossfade_enabled;
58static bool crossfade_active; 58static bool crossfade_active;
59static bool crossfade_init; 59static bool crossfade_init;
60static int crossfade_pos; 60static int crossfade_pos;
61static int crossfade_amount;
62static int crossfade_rem; 61static int crossfade_rem;
63 62
64/* Crossfade modes. If CFM_CROSSFADE is selected, normal 63/* Crossfade modes. If CFM_CROSSFADE is selected, normal
@@ -71,6 +70,9 @@ enum {
71 CFM_FLUSH 70 CFM_FLUSH
72}; 71};
73 72
73static int crossfade_fade_in_amount;
74static int crossfade_fade_in_rem;
75
74/* Structure we can use to queue pcm chunks in memory to be played 76/* Structure we can use to queue pcm chunks in memory to be played
75 * by the driver code. */ 77 * by the driver code. */
76struct pcmbufdesc 78struct pcmbufdesc
@@ -225,7 +227,7 @@ bool pcmbuf_is_lowdata(void)
225 return false; 227 return false;
226} 228}
227 229
228bool pcmbuf_crossfade_init(int type) 230bool pcmbuf_crossfade_init(void)
229{ 231{
230 if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled 232 if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
231 || crossfade_active || crossfade_init) { 233 || crossfade_active || crossfade_init) {
@@ -235,17 +237,8 @@ bool pcmbuf_crossfade_init(int type)
235 logf("pcmbuf_crossfade_init"); 237 logf("pcmbuf_crossfade_init");
236 pcmbuf_boost(true); 238 pcmbuf_boost(true);
237 239
238 switch (type) { 240 crossfade_mode = global_settings.crossfade_fade_out_mixmode
239 case CROSSFADE_MODE_CROSSFADE: 241 ? CFM_MIX : CFM_CROSSFADE;
240 crossfade_mode = CFM_CROSSFADE;
241 break;
242 case CROSSFADE_MODE_MIX:
243 crossfade_mode = CFM_MIX;
244 break;
245 default:
246 return false;
247 }
248
249 crossfade_init = true; 242 crossfade_init = true;
250 243
251 return true; 244 return true;
@@ -308,6 +301,9 @@ void pcmbuf_play_start(void)
308 pcm_play_data(pcmbuf_callback); 301 pcm_play_data(pcmbuf_callback);
309} 302}
310 303
304/**
305 * Commit samples waiting to the pcm buffer.
306 */
311void pcmbuf_flush_fillpos(void) 307void pcmbuf_flush_fillpos(void)
312{ 308{
313 int copy_n; 309 int copy_n;
@@ -335,9 +331,59 @@ void pcmbuf_flush_fillpos(void)
335 } 331 }
336} 332}
337 333
334/**
335 * Completely process the crossfade fade out effect with current pcm buffer.
336 */
337static void crossfade_process_buffer(
338 int fade_in_delay, int fade_out_delay, int fade_out_rem)
339{
340 int amount;
341 int pos;
342 short *buf;
343
344 /* Fade out the entire current buffer according to settings. */
345 amount = fade_out_rem;
346 pos = crossfade_pos + fade_out_delay*2;
347
348 while (fade_out_rem > 0 && crossfade_mode == CFM_CROSSFADE)
349 {
350 int blocksize = MIN(8192, fade_out_rem);
351 int factor = (fade_out_rem<<8)/amount;
352
353 /* Prevent pcmbuffer from wrapping. */
354 if (pos >= pcmbuf_size)
355 pos -= pcmbuf_size;
356 blocksize = MIN(pcmbuf_size - pos, blocksize);
357 buf = (short *)&audiobuffer[pos];
358
359 fade_out_rem -= blocksize;
360 pos += blocksize * 2;
361 while (blocksize > 0)
362 {
363 *buf = (*buf * factor) >> 8;
364 *buf++;
365 blocksize--;
366 }
367 //yield();
368 }
369
370 /* And finally set the mixing position where we should start fading in. */
371 crossfade_rem -= fade_in_delay;
372 crossfade_pos += fade_in_delay*2;
373 if (crossfade_pos >= pcmbuf_size)
374 crossfade_pos -= pcmbuf_size;
375 logf("process done!");
376}
377
378/**
379 * Initializes crossfader, calculates all necessary parameters and
380 * performs fade-out with the pcm buffer.
381 */
338static void crossfade_start(void) 382static void crossfade_start(void)
339{ 383{
340 int bytesleft = pcmbuf_unplayed_bytes; 384 int bytesleft = pcmbuf_unplayed_bytes;
385 int fade_out_rem = 0, fade_out_delay = 0;
386 int fade_in_delay = 0;
341 387
342 crossfade_init = 0; 388 crossfade_init = 0;
343 if (bytesleft < CHUNK_SIZE * 4) { 389 if (bytesleft < CHUNK_SIZE * 4) {
@@ -356,44 +402,125 @@ static void crossfade_start(void)
356 switch (crossfade_mode) { 402 switch (crossfade_mode) {
357 case CFM_MIX: 403 case CFM_MIX:
358 case CFM_CROSSFADE: 404 case CFM_CROSSFADE:
359 crossfade_amount = (bytesleft - (CHUNK_SIZE * 2))/2; 405 /* Initialize the crossfade buffer size. */
360 crossfade_rem = crossfade_amount; 406 crossfade_rem = (bytesleft - (CHUNK_SIZE * 2))/2;
407
408 /* Get fade out delay from settings. */
409 fade_out_delay = NATIVE_FREQUENCY
410 * global_settings.crossfade_fade_out_delay * 2;
411
412 /* Get fade out duration from settings. */
413 fade_out_rem = NATIVE_FREQUENCY
414 * global_settings.crossfade_fade_out_duration * 2;
415
416 /* Truncate fade out duration if necessary. */
417 if (fade_out_rem > crossfade_rem)
418 fade_out_rem = crossfade_rem;
419
420 /* We want only to modify the last part of the buffer. */
421 if (crossfade_rem > fade_out_rem + fade_out_delay)
422 crossfade_rem = fade_out_rem + fade_out_delay;
423
424 /* Get also fade in duration and delays from settings. */
425 crossfade_fade_in_rem = NATIVE_FREQUENCY
426 * global_settings.crossfade_fade_in_duration * 2;
427 crossfade_fade_in_amount = crossfade_fade_in_rem;
428
429 /* We should avoid to divide by zero. */
430 if (crossfade_fade_in_amount == 0)
431 crossfade_fade_in_amount = 1;
432
433 fade_in_delay = NATIVE_FREQUENCY
434 * global_settings.crossfade_fade_in_delay * 2;
435
436 /* Decrease the fade out delay if necessary. */
437 fade_out_delay += MIN(crossfade_rem -
438 fade_out_rem -
439 fade_out_delay, 0);
440 if (fade_out_delay < 0)
441 fade_out_delay = 0;
361 break ; 442 break ;
362 443
363 case CFM_FLUSH: 444 case CFM_FLUSH:
364 crossfade_amount = bytesleft /2; 445 crossfade_rem = bytesleft /2;
365 crossfade_rem = crossfade_amount;
366 break ; 446 break ;
367 } 447 }
368 448
369 crossfade_pos -= crossfade_amount*2; 449 crossfade_pos -= crossfade_rem*2;
370 if (crossfade_pos < 0) 450 if (crossfade_pos < 0)
371 crossfade_pos += pcmbuf_size; 451 crossfade_pos += pcmbuf_size;
452
453 if (crossfade_mode != CFM_FLUSH) {
454 /* Process the fade out part of the crossfade. */
455 crossfade_process_buffer(fade_in_delay, fade_out_delay, fade_out_rem);
456 }
457
458}
459
460/**
461 * Fades in samples passed to the function and inserts them
462 * to the pcm buffer.
463 */
464static void fade_insert(const short *inbuf, int length)
465{
466 int copy_n;
467 int factor;
468 int i, samples;
469 short *buf;
470
471 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)
472 <<8)/crossfade_fade_in_amount;
473
474 while (audiobuffer_free < length + audiobuffer_fillpos
475 + CHUNK_SIZE)
476 {
477 pcmbuf_boost(false);
478 sleep(1);
479 }
480
481 while (length > 0) {
482 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos -
483 audiobuffer_fillpos);
484 copy_n = MIN(CHUNK_SIZE - audiobuffer_fillpos, copy_n);
485
486 buf = (short *)&audiobuffer[audiobuffer_pos+audiobuffer_fillpos];
487 samples = copy_n / 2;
488 for (i = 0; i < samples; i++)
489 buf[i] = (inbuf[i] * factor) >> 8;
490
491 inbuf += samples;
492 audiobuffer_fillpos += copy_n;
493 length -= copy_n;
494
495 /* Pre-buffer to meet CHUNK_SIZE requirement */
496 if (audiobuffer_fillpos < CHUNK_SIZE && length == 0) {
497 break ;
498 }
499
500 pcmbuf_flush_fillpos();
501 }
372} 502}
373 503
504/**
505 * Fades in buf2 and mixes it with buf.
506 */
374static __inline 507static __inline
375int crossfade(short *buf, const short *buf2, int length) 508int crossfade(short *buf, const short *buf2, int length)
376{ 509{
377 int size, i; 510 int size, i;
378 int val1, val2; 511 int size_insert = 0;
512 int factor;
379 513
380 size = MIN(length, crossfade_rem); 514 size = MAX(0, MIN(length, crossfade_rem));
381 switch (crossfade_mode) { 515 switch (crossfade_mode) {
382 /* Mix two streams. */ 516 /* Fade in the current stream and mix it. */
383 case CFM_MIX: 517 case CFM_MIX:
384 /* Bias & add & clip. */
385 for (i = 0; i < size; i++) {
386 buf[i] = MIN(MAX(buf[i] + buf2[i], -32768), 32767);
387 }
388 break ;
389
390 /* Fade two streams. */
391 case CFM_CROSSFADE: 518 case CFM_CROSSFADE:
392 val1 = (crossfade_rem<<10)/crossfade_amount; 519 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)
393 val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount; 520 <<8)/crossfade_fade_in_amount;
394 521
395 for (i = 0; i < size; i++) { 522 for (i = 0; i < size; i++) {
396 buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10; 523 buf[i] = MIN(MAX(buf[i] + ((buf2[i] * factor) >> 8), -32768), 32767);
397 } 524 }
398 break ; 525 break ;
399 526
@@ -405,12 +532,20 @@ int crossfade(short *buf, const short *buf2, int length)
405 //memcpy((char *)buf, (char *)buf2, size*2); 532 //memcpy((char *)buf, (char *)buf2, size*2);
406 break ; 533 break ;
407 } 534 }
408 535
536 crossfade_fade_in_rem = MAX(0, crossfade_fade_in_rem - size);
409 crossfade_rem -= size; 537 crossfade_rem -= size;
410 if (crossfade_rem <= 0) 538 if (crossfade_rem <= 0)
411 crossfade_active = false; 539 {
412 540 size_insert = MAX(0, MIN(crossfade_fade_in_rem, length - size));
413 return size; 541 fade_insert(&buf2[size], size_insert*2);
542 crossfade_fade_in_rem -= size_insert;
543
544 if (crossfade_fade_in_rem <= 0)
545 crossfade_active = false;
546 }
547
548 return size + size_insert;
414} 549}
415 550
416static bool prepare_insert(long length) 551static bool prepare_insert(long length)
@@ -486,13 +621,12 @@ void pcmbuf_flush_buffer(long length)
486 } 621 }
487 622
488 while (length > 0) { 623 while (length > 0) {
624 pcmbuf_flush_fillpos();
489 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos); 625 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
490 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n); 626 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
491 audiobuffer_fillpos = copy_n; 627 audiobuffer_fillpos = copy_n;
492 buf += copy_n; 628 buf += copy_n;
493 length -= copy_n; 629 length -= copy_n;
494 if (length > 0)
495 pcmbuf_flush_fillpos();
496 } 630 }
497 } 631 }
498 632
@@ -537,13 +671,12 @@ bool pcmbuf_insert_buffer(char *buf, long length)
537 } 671 }
538 672
539 while (length > 0) { 673 while (length > 0) {
674 pcmbuf_flush_fillpos();
540 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos); 675 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
541 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n); 676 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
542 audiobuffer_fillpos = copy_n; 677 audiobuffer_fillpos = copy_n;
543 buf += copy_n; 678 buf += copy_n;
544 length -= copy_n; 679 length -= copy_n;
545 if (length > 0)
546 pcmbuf_flush_fillpos();
547 } 680 }
548 } 681 }
549 682
@@ -674,6 +807,9 @@ void pcmbuf_crossfade_enable(bool on_off)
674 807
675bool pcmbuf_is_crossfade_enabled(void) 808bool pcmbuf_is_crossfade_enabled(void)
676{ 809{
810 if (global_settings.crossfade == CROSSFADE_ENABLE_SHUFFLE)
811 return global_settings.playlist_shuffle;
812
677 return crossfade_enabled; 813 return crossfade_enabled;
678} 814}
679 815
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 629f969e7d..9031db60b1 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -43,7 +43,7 @@ void pcmbuf_set_boost_mode(bool state);
43bool pcmbuf_is_lowdata(void); 43bool pcmbuf_is_lowdata(void);
44void pcmbuf_flush_audio(void); 44void pcmbuf_flush_audio(void);
45void pcmbuf_play_start(void); 45void pcmbuf_play_start(void);
46bool pcmbuf_crossfade_init(int type); 46bool pcmbuf_crossfade_init(void);
47void pcmbuf_add_event(void (*event_handler)(void)); 47void pcmbuf_add_event(void (*event_handler)(void));
48unsigned int pcmbuf_get_latency(void); 48unsigned int pcmbuf_get_latency(void);
49bool pcmbuf_insert_buffer(char *buf, long length); 49bool pcmbuf_insert_buffer(char *buf, long length);
diff --git a/apps/playback.c b/apps/playback.c
index 8d869ceda3..61d0d62af8 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1441,8 +1441,7 @@ void audio_update_trackinfo(void)
1441 cur_ti->start_pos = 0; 1441 cur_ti->start_pos = 0;
1442 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready; 1442 ci.taginfo_ready = (bool *)&cur_ti->taginfo_ready;
1443 if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) { 1443 if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()) {
1444 pcmbuf_crossfade_init(new_track ? CROSSFADE_MODE_CROSSFADE 1444 pcmbuf_crossfade_init();
1445 : global_settings.crossfade);
1446 codec_track_changed(); 1445 codec_track_changed();
1447 } else { 1446 } else {
1448 pcmbuf_add_event(codec_track_changed); 1447 pcmbuf_add_event(codec_track_changed);
@@ -1706,7 +1705,7 @@ void audio_thread(void)
1706 ci.stop_codec = true; 1705 ci.stop_codec = true;
1707 ci.reload_codec = false; 1706 ci.reload_codec = false;
1708 ci.seek_time = 0; 1707 ci.seek_time = 0;
1709 pcmbuf_crossfade_init(CROSSFADE_MODE_CROSSFADE); 1708 pcmbuf_crossfade_init();
1710 while (audio_codec_loaded) 1709 while (audio_codec_loaded)
1711 yield(); 1710 yield();
1712 audio_play_start((int)ev.data); 1711 audio_play_start((int)ev.data);
@@ -2227,13 +2226,12 @@ void audio_set_buffer_margin(int setting)
2227} 2226}
2228 2227
2229/* Set crossfade & PCM buffer length. */ 2228/* Set crossfade & PCM buffer length. */
2230void audio_set_crossfade(int type) 2229void audio_set_crossfade(int enable)
2231{ 2230{
2232 long size; 2231 long size;
2233 bool was_playing = playing; 2232 bool was_playing = playing;
2234 int offset = 0; 2233 int offset = 0;
2235 static const int lookup[] = {1, 2, 4, 6, 8, 10, 12, 14}; 2234 int seconds = 1;
2236 int seconds = lookup[global_settings.crossfade_duration];
2237 2235
2238 if (!filebuf) 2236 if (!filebuf)
2239 return; /* Audio buffers not yet set up */ 2237 return; /* Audio buffers not yet set up */
@@ -2242,8 +2240,11 @@ void audio_set_crossfade(int type)
2242 if (playing) 2240 if (playing)
2243 offset = cur_ti->id3.offset; 2241 offset = cur_ti->id3.offset;
2244 2242
2245 if (type == CROSSFADE_MODE_OFF) 2243 if (enable)
2246 seconds = 1; 2244 {
2245 seconds = global_settings.crossfade_fade_out_delay
2246 + global_settings.crossfade_fade_out_duration;
2247 }
2247 2248
2248 /* Buffer has to be at least 2s long. */ 2249 /* Buffer has to be at least 2s long. */
2249 seconds += 2; 2250 seconds += 2;
@@ -2259,7 +2260,7 @@ void audio_set_crossfade(int type)
2259 if (was_playing) 2260 if (was_playing)
2260 splash(0, true, str(LANG_RESTARTING_PLAYBACK)); 2261 splash(0, true, str(LANG_RESTARTING_PLAYBACK));
2261 pcmbuf_init(size); 2262 pcmbuf_init(size);
2262 pcmbuf_crossfade_enable(type != CROSSFADE_MODE_OFF); 2263 pcmbuf_crossfade_enable(enable);
2263 reset_buffer(); 2264 reset_buffer();
2264 logf("abuf:%dB", pcmbuf_get_bufsize()); 2265 logf("abuf:%dB", pcmbuf_get_bufsize());
2265 logf("fbuf:%dB", filebuflen); 2266 logf("fbuf:%dB", filebuflen);
diff --git a/apps/settings.c b/apps/settings.c
index 870376c8b2..5eb434b31d 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -85,7 +85,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
85#include "dsp.h" 85#include "dsp.h"
86#endif 86#endif
87 87
88#define CONFIG_BLOCK_VERSION 28 88#define CONFIG_BLOCK_VERSION 29
89#define CONFIG_BLOCK_SIZE 512 89#define CONFIG_BLOCK_SIZE 512
90#define RTC_BLOCK_SIZE 44 90#define RTC_BLOCK_SIZE 44
91 91
@@ -417,10 +417,6 @@ static const struct bit_entry hd_bits[] =
417 {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"}, 417 {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
418#endif 418#endif
419 419
420#if CONFIG_CODEC == SWCODEC
421 {3, S_O(crossfade_duration), 0, "crossfade duration", "1s,2s,4s,6s,8s,10s,12s,14s"},
422#endif
423
424#if CONFIG_BACKLIGHT == BL_IRIVER 420#if CONFIG_BACKLIGHT == BL_IRIVER
425 /* backlight fading */ 421 /* backlight fading */
426 {2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"}, 422 {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[] =
436 {1, S_O(runtimedb), false, "gather runtime data", off_on }, 432 {1, S_O(runtimedb), false, "gather runtime data", off_on },
437 433
438#if CONFIG_CODEC == SWCODEC 434#if CONFIG_CODEC == SWCODEC
439 {2, S_O(crossfade), 0, "crossfade type", "off,crossfade,mix"},
440 {1, S_O(replaygain), false, "replaygain", off_on }, 435 {1, S_O(replaygain), false, "replaygain", off_on },
441 {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type", 436 {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
442 "track,album,track shuffle" }, 437 "track,album,track shuffle" },
443 {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on }, 438 {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
444 {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL }, 439 {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
445 {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" }, 440 {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
441 {2, S_O(crossfade), 0, "crossfade", "off,shuffle,always"},
442 {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
443 {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
444 {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
445 {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
446 {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
446#endif 447#endif
447#ifdef HAVE_DIRCACHE 448#ifdef HAVE_DIRCACHE
448 {1, S_O(dircache), false, "dircache", off_on }, 449 {1, S_O(dircache), false, "dircache", off_on },
diff --git a/apps/settings.h b/apps/settings.h
index 99254e377f..63349c646e 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -109,9 +109,8 @@
109#define TRIG_DURATION_COUNT 13 109#define TRIG_DURATION_COUNT 13
110extern const char * const trig_durations[TRIG_DURATION_COUNT]; 110extern const char * const trig_durations[TRIG_DURATION_COUNT];
111 111
112#define CROSSFADE_MODE_OFF 0 112#define CROSSFADE_ENABLE_SHUFFLE 1
113#define CROSSFADE_MODE_CROSSFADE 1 113#define CROSSFADE_ENABLE_ALWAYS 2
114#define CROSSFADE_MODE_MIX 2
115 114
116/* These define "virtual pointers", which could either be a literal string, 115/* These define "virtual pointers", which could either be a literal string,
117 or a mean a string ID if the pointer is in a certain range. 116 or a mean a string ID if the pointer is in a certain range.
@@ -157,8 +156,12 @@ struct user_settings
157 bool superbass; /* true/false */ 156 bool superbass; /* true/false */
158 157
159#if CONFIG_CODEC == SWCODEC 158#if CONFIG_CODEC == SWCODEC
160 int crossfade; 159 int crossfade; /* Enable crossfade (0=off,1=shuffle,2=always) */
161 int crossfade_duration; 160 int crossfade_fade_in_delay; /* Fade in delay (0-15s) */
161 int crossfade_fade_out_delay; /* Fade out delay (0-15s) */
162 int crossfade_fade_in_duration; /* Fade in duration (0-15s) */
163 int crossfade_fade_out_duration; /* Fade out duration (0-15s) */
164 int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */
162#endif 165#endif
163 166
164 int rec_quality; /* 0-7 */ 167 int rec_quality; /* 0-7 */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index b6d6b2bdac..65e40f9f10 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1110,44 +1110,6 @@ static bool id3_order(void)
1110 mpeg_id3_options); 1110 mpeg_id3_options);
1111} 1111}
1112 1112
1113#if CONFIG_CODEC == SWCODEC
1114static bool crossfade(void)
1115{
1116 static const struct opt_items names[] = {
1117 { STR(LANG_OFF) },
1118 { STR(LANG_CROSSFADE) },
1119 { STR(LANG_MIX) },
1120 };
1121 bool ret;
1122
1123 ret = set_option( str(LANG_CROSSFADE),
1124 &global_settings.crossfade, INT, names, 3, NULL);
1125 audio_set_crossfade(global_settings.crossfade);
1126
1127 return ret;
1128}
1129
1130static bool crossfade_duration(void)
1131{
1132 static const struct opt_items names[] = {
1133 { "1s", TALK_ID(1, UNIT_SEC) },
1134 { "2s", TALK_ID(2, UNIT_SEC) },
1135 { "4s", TALK_ID(4, UNIT_SEC) },
1136 { "6s", TALK_ID(6, UNIT_SEC) },
1137 { "8s", TALK_ID(8, UNIT_SEC) },
1138 { "10s", TALK_ID(10, UNIT_SEC) },
1139 { "12s", TALK_ID(12, UNIT_SEC) },
1140 { "14s", TALK_ID(14, UNIT_SEC) },
1141 };
1142 bool ret;
1143 ret=set_option( str(LANG_CROSSFADE_DURATION),
1144 &global_settings.crossfade_duration, INT, names, 8, NULL);
1145 audio_set_crossfade(global_settings.crossfade);
1146
1147 return ret;
1148}
1149#endif
1150
1151static bool next_folder(void) 1113static bool next_folder(void)
1152{ 1114{
1153 return set_bool( str(LANG_NEXT_FOLDER), &global_settings.next_folder ); 1115 return set_bool( str(LANG_NEXT_FOLDER), &global_settings.next_folder );
@@ -1239,6 +1201,120 @@ static bool replaygain_settings_menu(void)
1239 return result; 1201 return result;
1240} 1202}
1241 1203
1204static bool crossfade(void)
1205{
1206 static const struct opt_items names[] = {
1207 { STR(LANG_OFF) },
1208 { STR(LANG_SHUFFLE) },
1209 { STR(LANG_ALWAYS) },
1210 };
1211
1212 bool ret;
1213
1214 ret=set_option( str(LANG_CROSSFADE_ENABLE),
1215 &global_settings.crossfade, INT, names, 3, NULL);
1216
1217 audio_set_crossfade(global_settings.crossfade);
1218
1219 return ret;
1220}
1221
1222static const struct opt_items crossfade_time[] = {
1223 { "0s", TALK_ID(0, UNIT_SEC) },
1224 { "1s", TALK_ID(1, UNIT_SEC) },
1225 { "2s", TALK_ID(2, UNIT_SEC) },
1226 { "3s", TALK_ID(3, UNIT_SEC) },
1227 { "4s", TALK_ID(4, UNIT_SEC) },
1228 { "5s", TALK_ID(5, UNIT_SEC) },
1229 { "6s", TALK_ID(6, UNIT_SEC) },
1230 { "7s", TALK_ID(7, UNIT_SEC) },
1231 { "8s", TALK_ID(8, UNIT_SEC) },
1232 { "9s", TALK_ID(9, UNIT_SEC) },
1233 { "10s", TALK_ID(10, UNIT_SEC) },
1234 { "11s", TALK_ID(11, UNIT_SEC) },
1235 { "12s", TALK_ID(12, UNIT_SEC) },
1236 { "13s", TALK_ID(13, UNIT_SEC) },
1237 { "14s", TALK_ID(14, UNIT_SEC) },
1238 { "15s", TALK_ID(15, UNIT_SEC) },
1239};
1240
1241static bool crossfade_fade_in_delay(void)
1242{
1243 bool ret;
1244 ret=set_option( str(LANG_CROSSFADE_FADE_IN_DELAY),
1245 &global_settings.crossfade_fade_in_delay, INT, crossfade_time, 8, NULL);
1246 audio_set_crossfade(global_settings.crossfade);
1247
1248 return ret;
1249}
1250
1251static bool crossfade_fade_out_delay(void)
1252{
1253 bool ret;
1254 ret=set_option( str(LANG_CROSSFADE_FADE_OUT_DELAY),
1255 &global_settings.crossfade_fade_out_delay, INT, crossfade_time, 8, NULL);
1256 audio_set_crossfade(global_settings.crossfade);
1257
1258 return ret;
1259}
1260
1261static bool crossfade_fade_in_duration(void)
1262{
1263 bool ret;
1264 ret=set_option( str(LANG_CROSSFADE_FADE_IN_DURATION),
1265 &global_settings.crossfade_fade_in_duration, INT, crossfade_time, 16, NULL);
1266 audio_set_crossfade(global_settings.crossfade);
1267
1268 return ret;
1269}
1270
1271static bool crossfade_fade_out_duration(void)
1272{
1273 bool ret;
1274 ret=set_option( str(LANG_CROSSFADE_FADE_OUT_DURATION),
1275 &global_settings.crossfade_fade_out_duration, INT, crossfade_time, 16, NULL);
1276 audio_set_crossfade(global_settings.crossfade);
1277
1278 return ret;
1279}
1280
1281static bool crossfade_fade_out_mixmode(void)
1282{
1283 static const struct opt_items names[] = {
1284 { STR(LANG_CROSSFADE) },
1285 { STR(LANG_MIX) },
1286 };
1287 bool ret;
1288 ret=set_option( str(LANG_CROSSFADE_FADE_OUT_MODE),
1289 &global_settings.crossfade_fade_out_mixmode, INT, names, 2, NULL);
1290
1291 return ret;
1292}
1293
1294/**
1295 * Menu to configure the crossfade settings.
1296 */
1297static bool crossfade_settings_menu(void)
1298{
1299 int m;
1300 bool result;
1301
1302 static const struct menu_item items[] = {
1303 { ID2P(LANG_CROSSFADE_ENABLE), crossfade },
1304 { ID2P(LANG_CROSSFADE_FADE_IN_DELAY), crossfade_fade_in_delay },
1305 { ID2P(LANG_CROSSFADE_FADE_IN_DURATION), crossfade_fade_in_duration },
1306 { ID2P(LANG_CROSSFADE_FADE_OUT_DELAY), crossfade_fade_out_delay },
1307 { ID2P(LANG_CROSSFADE_FADE_OUT_DURATION), crossfade_fade_out_duration },
1308 { ID2P(LANG_CROSSFADE_FADE_OUT_MODE), crossfade_fade_out_mixmode },
1309 };
1310
1311 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
1312 NULL, NULL, NULL);
1313 result = menu_run(m);
1314 menu_exit(m);
1315 return result;
1316}
1317
1242static bool beep(void) 1318static bool beep(void)
1243{ 1319{
1244 static const struct opt_items names[] = { 1320 static const struct opt_items names[] = {
@@ -1289,8 +1365,7 @@ static bool playback_settings_menu(void)
1289 { ID2P(LANG_MP3BUFFER_MARGIN), buffer_margin }, 1365 { ID2P(LANG_MP3BUFFER_MARGIN), buffer_margin },
1290 { ID2P(LANG_FADE_ON_STOP), set_fade_on_stop }, 1366 { ID2P(LANG_FADE_ON_STOP), set_fade_on_stop },
1291#if CONFIG_CODEC == SWCODEC 1367#if CONFIG_CODEC == SWCODEC
1292 { ID2P(LANG_CROSSFADE), crossfade }, 1368 { ID2P(LANG_CROSSFADE), crossfade_settings_menu },
1293 { ID2P(LANG_CROSSFADE_DURATION), crossfade_duration },
1294 { ID2P(LANG_REPLAYGAIN), replaygain_settings_menu }, 1369 { ID2P(LANG_REPLAYGAIN), replaygain_settings_menu },
1295 { ID2P(LANG_BEEP), beep }, 1370 { ID2P(LANG_BEEP), beep },
1296#endif 1371#endif