diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2005-11-06 16:40:20 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2005-11-06 16:40:20 +0000 |
commit | e7461b36092611cca29697f7aca59f2247923d90 (patch) | |
tree | 7949b01457e3a61d9863e91217f9ef00032f11d6 /apps/pcmbuf.c | |
parent | ce1312e383e200b2745ffb118bc85f44e37d6a87 (diff) | |
download | rockbox-e7461b36092611cca29697f7aca59f2247923d90.tar.gz rockbox-e7461b36092611cca29697f7aca59f2247923d90.zip |
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
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r-- | apps/pcmbuf.c | 216 |
1 files changed, 176 insertions, 40 deletions
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 | ||