diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/lang/english.lang | 42 | ||||
-rw-r--r-- | apps/lang/finnish.lang | 44 | ||||
-rw-r--r-- | apps/pcmbuf.c | 216 | ||||
-rw-r--r-- | apps/pcmbuf.h | 2 | ||||
-rw-r--r-- | apps/playback.c | 19 | ||||
-rw-r--r-- | apps/settings.c | 13 | ||||
-rw-r--r-- | apps/settings.h | 13 | ||||
-rw-r--r-- | apps/settings_menu.c | 155 |
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: "" | |||
3168 | new: | 3168 | new: |
3169 | 3169 | ||
3170 | id: LANG_CROSSFADE_DURATION | 3170 | id: LANG_CROSSFADE_DURATION |
3171 | desc: in playback settings | 3171 | desc: DEPRECATED |
3172 | eng: "Crossfade duration" | 3172 | eng: "" |
3173 | voice: "Crossfade duration" | 3173 | voice: "" |
3174 | new: | 3174 | new: |
3175 | 3175 | ||
3176 | id: LANG_MIX | 3176 | id: LANG_MIX |
@@ -3316,3 +3316,39 @@ desc: when booting up and rebuilding the cache | |||
3316 | eng: "Scanning disk..." | 3316 | eng: "Scanning disk..." |
3317 | voice: "" | 3317 | voice: "" |
3318 | new: | 3318 | new: |
3319 | |||
3320 | id: LANG_CROSSFADE_ENABLE | ||
3321 | desc: in crossfade settings menu | ||
3322 | eng: "Enable crossfade" | ||
3323 | voice: "Enable crossfade" | ||
3324 | new: | ||
3325 | |||
3326 | id: LANG_CROSSFADE_FADE_IN_DELAY | ||
3327 | desc: in crossfade settings menu | ||
3328 | eng: "Fade in delay" | ||
3329 | voice: "Fade in delay" | ||
3330 | new: | ||
3331 | |||
3332 | id: LANG_CROSSFADE_FADE_OUT_DELAY | ||
3333 | desc: in crossfade settings menu | ||
3334 | eng: "Fade out delay" | ||
3335 | voice: "Fade out delay" | ||
3336 | new: | ||
3337 | |||
3338 | id: LANG_CROSSFADE_FADE_IN_DURATION | ||
3339 | desc: in crossfade settings menu | ||
3340 | eng: "Fade in duration" | ||
3341 | voice: "Fade in duration" | ||
3342 | new: | ||
3343 | |||
3344 | id: LANG_CROSSFADE_FADE_OUT_DURATION | ||
3345 | desc: in crossfade settings menu | ||
3346 | eng: "Fade out duration" | ||
3347 | voice: "Fade out duration" | ||
3348 | new: | ||
3349 | |||
3350 | id: LANG_CROSSFADE_FADE_OUT_MODE | ||
3351 | desc: in crossfade settings menu | ||
3352 | eng: "Fade out mode" | ||
3353 | voice: "Fade out mode" | ||
3354 | new: | ||
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" | |||
3144 | new: "Ristivaihto" | 3144 | new: "Ristivaihto" |
3145 | 3145 | ||
3146 | id: LANG_CROSSFADE_DURATION | 3146 | id: LANG_CROSSFADE_DURATION |
3147 | desc: in playback settings | 3147 | desc: DEPRECATED |
3148 | eng: "Crossfade duration" | 3148 | eng: "" |
3149 | voice: "Ristivaihdon kesto" | 3149 | voice: "" |
3150 | new: "Ristivaihdon kesto" | 3150 | new: "" |
3151 | 3151 | ||
3152 | id: LANG_SHUFFLE_PLAYLIST | 3152 | id: LANG_SHUFFLE_PLAYLIST |
3153 | desc: in playlist menu, reshuffles the order in which songs are played | 3153 | desc: in playlist menu, reshuffles the order in which songs are played |
@@ -3347,3 +3347,39 @@ desc: when booting up and rebuilding the cache | |||
3347 | eng: "Scanning disk..." | 3347 | eng: "Scanning disk..." |
3348 | voice: "" | 3348 | voice: "" |
3349 | new: "Ladataan hakemistopuu..." | 3349 | new: "Ladataan hakemistopuu..." |
3350 | |||
3351 | id: LANG_CROSSFADE_ENABLE | ||
3352 | desc: in crossfade settings menu | ||
3353 | eng: "Enable crossfade" | ||
3354 | voice: "Aktivoi ristivaihto" | ||
3355 | new: "Aktivoi ristivaihto" | ||
3356 | |||
3357 | id: LANG_CROSSFADE_FADE_IN_DELAY | ||
3358 | desc: in crossfade settings menu | ||
3359 | eng: "Fade in delay" | ||
3360 | voice: "Sisäänhäivytyksen viive" | ||
3361 | new: "Sisäänhäivytyksen viive" | ||
3362 | |||
3363 | id: LANG_CROSSFADE_FADE_OUT_DELAY | ||
3364 | desc: in crossfade settings menu | ||
3365 | eng: "Fade out delay" | ||
3366 | voice: "Poishäivytyksen viive" | ||
3367 | new: "Poishäivytyksen viive" | ||
3368 | |||
3369 | id: LANG_CROSSFADE_FADE_IN_DURATION | ||
3370 | desc: in crossfade settings menu | ||
3371 | eng: "Fade in duration" | ||
3372 | voice: "Sisäänhäivytyksen kesto" | ||
3373 | new: "Sisäänhäivytyksen kesto" | ||
3374 | |||
3375 | id: LANG_CROSSFADE_FADE_OUT_DURATION | ||
3376 | desc: in crossfade settings menu | ||
3377 | eng: "Fade out duration" | ||
3378 | voice: "Poishäivytyksen kesto" | ||
3379 | new: "Poishäivytyksen kesto" | ||
3380 | |||
3381 | id: LANG_CROSSFADE_FADE_OUT_MODE | ||
3382 | desc: in crossfade settings menu | ||
3383 | eng: "Fade out mode" | ||
3384 | voice: "Poishäivytyksen tyyli" | ||
3385 | new: "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; | |||
58 | static bool crossfade_active; | 58 | static bool crossfade_active; |
59 | static bool crossfade_init; | 59 | static bool crossfade_init; |
60 | static int crossfade_pos; | 60 | static int crossfade_pos; |
61 | static int crossfade_amount; | ||
62 | static int crossfade_rem; | 61 | static 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 | ||
73 | static int crossfade_fade_in_amount; | ||
74 | static 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. */ |
76 | struct pcmbufdesc | 78 | struct pcmbufdesc |
@@ -225,7 +227,7 @@ bool pcmbuf_is_lowdata(void) | |||
225 | return false; | 227 | return false; |
226 | } | 228 | } |
227 | 229 | ||
228 | bool pcmbuf_crossfade_init(int type) | 230 | bool 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 | */ | ||
311 | void pcmbuf_flush_fillpos(void) | 307 | void 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 | */ | ||
337 | static 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 | */ | ||
338 | static void crossfade_start(void) | 382 | static 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 | */ | ||
464 | static 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 | */ | ||
374 | static __inline | 507 | static __inline |
375 | int crossfade(short *buf, const short *buf2, int length) | 508 | int 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 | ||
416 | static bool prepare_insert(long length) | 551 | static 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 | ||
675 | bool pcmbuf_is_crossfade_enabled(void) | 808 | bool 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); | |||
43 | bool pcmbuf_is_lowdata(void); | 43 | bool pcmbuf_is_lowdata(void); |
44 | void pcmbuf_flush_audio(void); | 44 | void pcmbuf_flush_audio(void); |
45 | void pcmbuf_play_start(void); | 45 | void pcmbuf_play_start(void); |
46 | bool pcmbuf_crossfade_init(int type); | 46 | bool pcmbuf_crossfade_init(void); |
47 | void pcmbuf_add_event(void (*event_handler)(void)); | 47 | void pcmbuf_add_event(void (*event_handler)(void)); |
48 | unsigned int pcmbuf_get_latency(void); | 48 | unsigned int pcmbuf_get_latency(void); |
49 | bool pcmbuf_insert_buffer(char *buf, long length); | 49 | bool 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. */ |
2230 | void audio_set_crossfade(int type) | 2229 | void 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 |
110 | extern const char * const trig_durations[TRIG_DURATION_COUNT]; | 110 | extern 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 | ||
1114 | static 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 | |||
1130 | static 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 | |||
1151 | static bool next_folder(void) | 1113 | static 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 | ||
1204 | static 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 | |||
1222 | static 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 | |||
1241 | static 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 | |||
1251 | static 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 | |||
1261 | static 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 | |||
1271 | static 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 | |||
1281 | static 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 | */ | ||
1297 | static 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 | |||
1242 | static bool beep(void) | 1318 | static 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 |