diff options
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r-- | firmware/pcm_playback.c | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 99a71c2f41..ab4f0c0375 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -56,6 +56,11 @@ static volatile size_t audiobuffer_free; | |||
56 | static size_t audiobuffer_fillpos; | 56 | static size_t audiobuffer_fillpos; |
57 | static bool boost_mode; | 57 | static bool boost_mode; |
58 | 58 | ||
59 | static bool crossfade_active; | ||
60 | static int crossfade_pos; | ||
61 | static int crossfade_amount; | ||
62 | static int crossfade_rem; | ||
63 | |||
59 | static unsigned char *next_start; | 64 | static unsigned char *next_start; |
60 | static long next_size; | 65 | static long next_size; |
61 | 66 | ||
@@ -106,6 +111,9 @@ void pcm_boost(bool state) | |||
106 | { | 111 | { |
107 | static bool boost_state = false; | 112 | static bool boost_state = false; |
108 | 113 | ||
114 | if (crossfade_active) | ||
115 | return ; | ||
116 | |||
109 | if (state != boost_state) { | 117 | if (state != boost_state) { |
110 | cpu_boost(state); | 118 | cpu_boost(state); |
111 | boost_state = state; | 119 | boost_state = state; |
@@ -334,6 +342,7 @@ void pcm_watermark_callback(int bytes_left) | |||
334 | 342 | ||
335 | /* Fill audio buffer by boosting cpu */ | 343 | /* Fill audio buffer by boosting cpu */ |
336 | pcm_boost(true); | 344 | pcm_boost(true); |
345 | crossfade_active = false; | ||
337 | } | 346 | } |
338 | 347 | ||
339 | void pcm_set_boost_mode(bool state) | 348 | void pcm_set_boost_mode(bool state) |
@@ -373,11 +382,43 @@ bool pcm_is_lowdata(void) | |||
373 | return false; | 382 | return false; |
374 | } | 383 | } |
375 | 384 | ||
385 | void pcm_crossfade_start(void) | ||
386 | { | ||
387 | if (audiobuffer_free > CHUNK_SIZE * 4) { | ||
388 | return ; | ||
389 | } | ||
390 | pcm_boost(true); | ||
391 | crossfade_active = true; | ||
392 | crossfade_pos = audiobuffer_pos; | ||
393 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - CHUNK_SIZE * 22)/2; | ||
394 | crossfade_rem = crossfade_amount; | ||
395 | audiobuffer_fillpos = 0; | ||
396 | |||
397 | crossfade_pos -= crossfade_amount*2; | ||
398 | if (crossfade_pos < 0) | ||
399 | crossfade_pos = PCMBUF_SIZE + crossfade_pos; | ||
400 | } | ||
401 | |||
402 | static __inline | ||
403 | void crossfade(short *buf, const short *buf2, int length) | ||
404 | { | ||
405 | while (length--) { | ||
406 | *buf = (int)((*buf * ((crossfade_rem)*1000/crossfade_amount))/1000); | ||
407 | *buf += (int)((*buf2 * ((crossfade_amount-crossfade_rem)*1000/crossfade_amount))/1000); | ||
408 | buf++; | ||
409 | buf2++; | ||
410 | if (--crossfade_rem <= 0) { | ||
411 | crossfade_active = false; | ||
412 | break ; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
376 | bool audiobuffer_insert(char *buf, size_t length) | 417 | bool audiobuffer_insert(char *buf, size_t length) |
377 | { | 418 | { |
378 | size_t copy_n = 0; | 419 | size_t copy_n = 0; |
379 | 420 | ||
380 | if (audiobuffer_free < length + CHUNK_SIZE) { | 421 | if (audiobuffer_free < length + CHUNK_SIZE && !crossfade_active) { |
381 | if (!boost_mode) | 422 | if (!boost_mode) |
382 | pcm_boost(false); | 423 | pcm_boost(false); |
383 | return false; | 424 | return false; |
@@ -385,19 +426,35 @@ bool audiobuffer_insert(char *buf, size_t length) | |||
385 | 426 | ||
386 | if (!pcm_is_playing() && !pcm_paused) { | 427 | if (!pcm_is_playing() && !pcm_paused) { |
387 | pcm_boost(true); | 428 | pcm_boost(true); |
429 | crossfade_active = false; | ||
388 | if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*2) | 430 | if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*2) |
389 | pcm_play_start(); | 431 | pcm_play_start(); |
390 | } | 432 | } |
391 | 433 | ||
392 | while (length > 0) { | 434 | while (length > 0) { |
393 | copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos - | 435 | if (!crossfade_active) { |
394 | audiobuffer_fillpos); | 436 | copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos - |
395 | copy_n = MIN(CHUNK_SIZE, copy_n); | 437 | audiobuffer_fillpos); |
396 | memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos], | 438 | copy_n = MIN(CHUNK_SIZE, copy_n); |
397 | buf, copy_n); | 439 | |
398 | buf += copy_n; | 440 | memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos], |
399 | audiobuffer_free -= copy_n; | 441 | buf, copy_n); |
400 | length -= copy_n; | 442 | buf += copy_n; |
443 | audiobuffer_free -= copy_n; | ||
444 | length -= copy_n; | ||
445 | |||
446 | } else { | ||
447 | copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); | ||
448 | |||
449 | crossfade((short *)&audiobuffer[crossfade_pos], | ||
450 | (const short *)buf, copy_n/2); | ||
451 | buf += copy_n; | ||
452 | length -= copy_n; | ||
453 | crossfade_pos += copy_n; | ||
454 | if (crossfade_pos >= PCMBUF_SIZE) | ||
455 | crossfade_pos -= PCMBUF_SIZE; | ||
456 | continue ; | ||
457 | } | ||
401 | 458 | ||
402 | /* Pre-buffer to meet CHUNK_SIZE requirement */ | 459 | /* Pre-buffer to meet CHUNK_SIZE requirement */ |
403 | if (copy_n + audiobuffer_fillpos < CHUNK_SIZE && length == 0) { | 460 | if (copy_n + audiobuffer_fillpos < CHUNK_SIZE && length == 0) { |
@@ -452,6 +509,7 @@ void pcm_play_start(void) | |||
452 | int size; | 509 | int size; |
453 | char *start; | 510 | char *start; |
454 | 511 | ||
512 | crossfade_active = false; | ||
455 | if(!pcm_is_playing()) | 513 | if(!pcm_is_playing()) |
456 | { | 514 | { |
457 | size = MIN(desc->size, 32768); | 515 | size = MIN(desc->size, 32768); |