diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-26 19:41:29 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2005-06-26 19:41:29 +0000 |
commit | d8cb703b1e86c9f910211a976d8bed0c7a99379a (patch) | |
tree | 6db3b698d83e639974bd6603225ff11891652113 /firmware | |
parent | 316eb6538e2fc88efa93248deb761679071409f1 (diff) | |
download | rockbox-d8cb703b1e86c9f910211a976d8bed0c7a99379a.tar.gz rockbox-d8cb703b1e86c9f910211a976d8bed0c7a99379a.zip |
Initial DSP implementation. DSP supports resampling audio stream from
codecs (currently works corrently only with mp3's, somebody should fix
that).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6877 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/pcm_playback.h | 8 | ||||
-rw-r--r-- | firmware/pcm_playback.c | 133 |
2 files changed, 120 insertions, 21 deletions
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index aa29601f70..3fe60670b3 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h | |||
@@ -19,6 +19,10 @@ | |||
19 | #ifndef PCM_PLAYBACK_H | 19 | #ifndef PCM_PLAYBACK_H |
20 | #define PCM_PLAYBACK_H | 20 | #define PCM_PLAYBACK_H |
21 | 21 | ||
22 | /* Guard buffer for crossfader when dsp is enabled. */ | ||
23 | #define PCMBUF_GUARD 32768 | ||
24 | |||
25 | /* PCM audio buffer. */ | ||
22 | #define PCMBUF_SIZE (1*1024*1024) | 26 | #define PCMBUF_SIZE (1*1024*1024) |
23 | 27 | ||
24 | void pcm_init(void); | 28 | void pcm_init(void); |
@@ -44,7 +48,9 @@ bool pcm_is_lowdata(void); | |||
44 | bool pcm_crossfade_init(void); | 48 | bool pcm_crossfade_init(void); |
45 | void audiobuffer_add_event(void (*event_handler)(void)); | 49 | void audiobuffer_add_event(void (*event_handler)(void)); |
46 | unsigned int audiobuffer_get_latency(void); | 50 | unsigned int audiobuffer_get_latency(void); |
47 | bool audiobuffer_insert(char *buf, size_t length); | 51 | bool pcm_insert_buffer(char *buf, size_t length); |
52 | void pcm_flush_buffer(size_t length); | ||
53 | void* pcm_request_buffer(size_t length, size_t *realsize); | ||
48 | bool pcm_is_crossfade_enabled(void); | 54 | bool pcm_is_crossfade_enabled(void); |
49 | void pcm_crossfade_enable(bool on_off); | 55 | void pcm_crossfade_enable(bool on_off); |
50 | 56 | ||
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 24fc5d4530..12ecfd14e2 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -67,6 +67,7 @@ static int crossfade_pos; | |||
67 | static int crossfade_amount; | 67 | static int crossfade_amount; |
68 | static int crossfade_rem; | 68 | static int crossfade_rem; |
69 | 69 | ||
70 | static char *guardbuf; | ||
70 | static void (*pcm_event_handler)(void); | 71 | static void (*pcm_event_handler)(void); |
71 | 72 | ||
72 | static unsigned char *next_start; | 73 | static unsigned char *next_start; |
@@ -258,7 +259,6 @@ void pcm_play_pause(bool play) | |||
258 | IIS2CONFIG = 0x800; | 259 | IIS2CONFIG = 0x800; |
259 | } | 260 | } |
260 | pcm_paused = !play; | 261 | pcm_paused = !play; |
261 | pcm_boost(false); | ||
262 | } | 262 | } |
263 | 263 | ||
264 | bool pcm_is_playing(void) | 264 | bool pcm_is_playing(void) |
@@ -401,15 +401,8 @@ bool pcm_crossfade_init(void) | |||
401 | 401 | ||
402 | } | 402 | } |
403 | 403 | ||
404 | static void crossfade_start(void) | 404 | void pcm_flush_fillpos(void) |
405 | { | 405 | { |
406 | if (!crossfade_init) | ||
407 | return ; | ||
408 | |||
409 | crossfade_init = 0; | ||
410 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6) | ||
411 | return ; | ||
412 | |||
413 | if (audiobuffer_fillpos) { | 406 | if (audiobuffer_fillpos) { |
414 | while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], | 407 | while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], |
415 | audiobuffer_fillpos, pcm_event_handler)) { | 408 | audiobuffer_fillpos, pcm_event_handler)) { |
@@ -419,13 +412,26 @@ static void crossfade_start(void) | |||
419 | audiobuffer_pos += audiobuffer_fillpos; | 412 | audiobuffer_pos += audiobuffer_fillpos; |
420 | if (audiobuffer_pos >= PCMBUF_SIZE) | 413 | if (audiobuffer_pos >= PCMBUF_SIZE) |
421 | audiobuffer_pos -= PCMBUF_SIZE; | 414 | audiobuffer_pos -= PCMBUF_SIZE; |
415 | audiobuffer_free -= audiobuffer_fillpos; | ||
416 | audiobuffer_fillpos = 0; | ||
422 | } | 417 | } |
418 | } | ||
419 | |||
420 | static void crossfade_start(void) | ||
421 | { | ||
422 | if (!crossfade_init) | ||
423 | return ; | ||
424 | |||
425 | crossfade_init = 0; | ||
426 | if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6) | ||
427 | return ; | ||
428 | |||
429 | pcm_flush_fillpos(); | ||
423 | pcm_boost(true); | 430 | pcm_boost(true); |
424 | crossfade_active = true; | 431 | crossfade_active = true; |
425 | crossfade_pos = audiobuffer_pos; | 432 | crossfade_pos = audiobuffer_pos; |
426 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; | 433 | crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; |
427 | crossfade_rem = crossfade_amount; | 434 | crossfade_rem = crossfade_amount; |
428 | audiobuffer_fillpos = 0; | ||
429 | 435 | ||
430 | crossfade_pos -= crossfade_amount*2; | 436 | crossfade_pos -= crossfade_amount*2; |
431 | if (crossfade_pos < 0) | 437 | if (crossfade_pos < 0) |
@@ -451,12 +457,11 @@ int crossfade(short *buf, const short *buf2, int length) | |||
451 | return size; | 457 | return size; |
452 | } | 458 | } |
453 | 459 | ||
454 | bool audiobuffer_insert(char *buf, size_t length) | 460 | inline static bool prepare_insert(size_t length) |
455 | { | 461 | { |
456 | size_t copy_n = 0; | ||
457 | |||
458 | crossfade_start(); | 462 | crossfade_start(); |
459 | if (audiobuffer_free < length + CHUNK_SIZE && !crossfade_active) { | 463 | if (audiobuffer_free < length + audiobuffer_fillpos |
464 | + CHUNK_SIZE && !crossfade_active) { | ||
460 | pcm_boost(false); | 465 | pcm_boost(false); |
461 | return false; | 466 | return false; |
462 | } | 467 | } |
@@ -467,7 +472,94 @@ bool audiobuffer_insert(char *buf, size_t length) | |||
467 | if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*4) | 472 | if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*4) |
468 | pcm_play_start(); | 473 | pcm_play_start(); |
469 | } | 474 | } |
475 | |||
476 | return true; | ||
477 | } | ||
478 | |||
479 | void* pcm_request_buffer(size_t length, size_t *realsize) | ||
480 | { | ||
481 | void *ptr = NULL; | ||
482 | |||
483 | if (!prepare_insert(length)) { | ||
484 | *realsize = 0; | ||
485 | return NULL; | ||
486 | } | ||
487 | |||
488 | if (crossfade_active) { | ||
489 | *realsize = MIN(length, PCMBUF_GUARD); | ||
490 | ptr = &guardbuf[0]; | ||
491 | } else { | ||
492 | *realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos | ||
493 | - audiobuffer_fillpos); | ||
494 | if (*realsize < length) { | ||
495 | *realsize += MIN((long)(length - *realsize), PCMBUF_GUARD); | ||
496 | //logf("gbr:%d/%d", *realsize, length); | ||
497 | } | ||
498 | ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos]; | ||
499 | } | ||
500 | |||
501 | return ptr; | ||
502 | } | ||
503 | |||
504 | void pcm_flush_buffer(size_t length) | ||
505 | { | ||
506 | int copy_n; | ||
507 | char *buf; | ||
508 | |||
509 | if (crossfade_active) { | ||
510 | buf = &guardbuf[0]; | ||
511 | length = MIN(length, PCMBUF_GUARD); | ||
512 | while (length > 0 && crossfade_active) { | ||
513 | copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); | ||
514 | copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos], | ||
515 | (const short *)buf, copy_n/2); | ||
516 | buf += copy_n; | ||
517 | length -= copy_n; | ||
518 | crossfade_pos += copy_n; | ||
519 | if (crossfade_pos >= PCMBUF_SIZE) | ||
520 | crossfade_pos -= PCMBUF_SIZE; | ||
521 | } | ||
522 | |||
523 | if (length > 0) { | ||
524 | memcpy(&audiobuffer[audiobuffer_pos], buf, length); | ||
525 | audiobuffer_fillpos = length; | ||
526 | goto try_flush; | ||
527 | } | ||
528 | } else { | ||
529 | /* if (length == 0) { | ||
530 | pcm_flush_fillpos(); | ||
531 | audiobuffer_pos = 0; | ||
532 | return ; | ||
533 | } */ | ||
534 | |||
535 | audiobuffer_fillpos += length; | ||
536 | |||
537 | try_flush: | ||
538 | if (audiobuffer_fillpos < CHUNK_SIZE && PCMBUF_SIZE | ||
539 | - audiobuffer_pos - audiobuffer_fillpos > 0) | ||
540 | return ; | ||
541 | |||
542 | copy_n = MIN((long)(audiobuffer_fillpos - (PCMBUF_SIZE | ||
543 | - audiobuffer_pos)), PCMBUF_GUARD); | ||
544 | if (copy_n > 0) { | ||
545 | //logf("guard buf used:%d", copy_n); | ||
546 | audiobuffer_fillpos -= copy_n; | ||
547 | pcm_flush_fillpos(); | ||
548 | memcpy(&audiobuffer[0], &guardbuf[0], copy_n); | ||
549 | audiobuffer_fillpos = copy_n; | ||
550 | goto try_flush; | ||
551 | } | ||
552 | pcm_flush_fillpos(); | ||
553 | } | ||
554 | } | ||
470 | 555 | ||
556 | bool pcm_insert_buffer(char *buf, size_t length) | ||
557 | { | ||
558 | size_t copy_n = 0; | ||
559 | |||
560 | if (!prepare_insert(length)) | ||
561 | return false; | ||
562 | |||
471 | while (length > 0) { | 563 | while (length > 0) { |
472 | if (crossfade_active) { | 564 | if (crossfade_active) { |
473 | copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); | 565 | copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); |
@@ -521,7 +613,8 @@ bool audiobuffer_insert(char *buf, size_t length) | |||
521 | void pcm_play_init(void) | 613 | void pcm_play_init(void) |
522 | { | 614 | { |
523 | audiobuffer = &audiobuf[(audiobufend - audiobuf) - | 615 | audiobuffer = &audiobuf[(audiobufend - audiobuf) - |
524 | PCMBUF_SIZE]; | 616 | PCMBUF_SIZE - PCMBUF_GUARD]; |
617 | guardbuf = &audiobuffer[PCMBUF_SIZE]; | ||
525 | audiobuffer_free = PCMBUF_SIZE; | 618 | audiobuffer_free = PCMBUF_SIZE; |
526 | audiobuffer_pos = 0; | 619 | audiobuffer_pos = 0; |
527 | audiobuffer_fillpos = 0; | 620 | audiobuffer_fillpos = 0; |
@@ -532,11 +625,6 @@ void pcm_play_init(void) | |||
532 | crossfade_active = false; | 625 | crossfade_active = false; |
533 | crossfade_init = false; | 626 | crossfade_init = false; |
534 | pcm_event_handler = NULL; | 627 | pcm_event_handler = NULL; |
535 | if (crossfade_enabled) { | ||
536 | pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback); | ||
537 | } else { | ||
538 | pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback); | ||
539 | } | ||
540 | } | 628 | } |
541 | 629 | ||
542 | void pcm_crossfade_enable(bool on_off) | 630 | void pcm_crossfade_enable(bool on_off) |
@@ -555,6 +643,11 @@ void pcm_play_start(void) | |||
555 | int size; | 643 | int size; |
556 | char *start; | 644 | char *start; |
557 | 645 | ||
646 | if (crossfade_enabled) { | ||
647 | pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback); | ||
648 | } else { | ||
649 | pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback); | ||
650 | } | ||
558 | crossfade_active = false; | 651 | crossfade_active = false; |
559 | if(!pcm_is_playing()) | 652 | if(!pcm_is_playing()) |
560 | { | 653 | { |