diff options
author | Andy <andy@rockbox.org> | 2005-12-02 01:04:03 +0000 |
---|---|---|
committer | Andy <andy@rockbox.org> | 2005-12-02 01:04:03 +0000 |
commit | 1e4d1f8de7a523d34c064f7f4a6e7f001d55bb7f (patch) | |
tree | 3488e91c68d693513bf42a4e5ffb5b75a4a7b8d9 /firmware/pcm_record.c | |
parent | 9758911be0c63de3dc5e42e9720f933effe5ad87 (diff) | |
download | rockbox-1e4d1f8de7a523d34c064f7f4a6e7f001d55bb7f.tar.gz rockbox-1e4d1f8de7a523d34c064f7f4a6e7f001d55bb7f.zip |
iRiver recording changes:
- Added Peakmeter in recording screen
- Fix for stop bug
- Fix for playback peakmeter not working after recording
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8120 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/pcm_record.c')
-rw-r--r-- | firmware/pcm_record.c | 135 |
1 files changed, 81 insertions, 54 deletions
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 1200669456..66ac747536 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -56,18 +56,17 @@ static volatile bool is_error; /* An error has occured */ | |||
56 | 56 | ||
57 | static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ | 57 | static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ |
58 | static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ | 58 | static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ |
59 | static volatile int int_count; /* Number of DMA completed interrupts */ | ||
60 | static volatile int error_count; /* Number of DMA errors */ | 59 | static volatile int error_count; /* Number of DMA errors */ |
61 | 60 | ||
62 | static unsigned long record_start_time; /* Value of current_tick when recording was started */ | 61 | static unsigned long record_start_time; /* Value of current_tick when recording was started */ |
63 | static unsigned long pause_start_time; /* Value of current_tick when pause was started */ | 62 | static unsigned long pause_start_time; /* Value of current_tick when pause was started */ |
64 | 63 | ||
65 | static bool show_waveform; | ||
66 | |||
67 | static int wav_file; | 64 | static int wav_file; |
68 | static char recording_filename[MAX_PATH]; | 65 | static char recording_filename[MAX_PATH]; |
69 | 66 | ||
70 | static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; | 67 | static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; |
68 | |||
69 | static int peak_left, peak_right; | ||
71 | 70 | ||
72 | /***************************************************************************/ | 71 | /***************************************************************************/ |
73 | 72 | ||
@@ -75,17 +74,10 @@ static bool init_done, close_done, record_done, stop_done, pause_done, resume_do | |||
75 | Some estimates: | 74 | Some estimates: |
76 | Normal recording rate: 44100 HZ * 4 = 176 KB/s | 75 | Normal recording rate: 44100 HZ * 4 = 176 KB/s |
77 | Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk | 76 | Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk |
78 | CHUNK_SIZE: 65536 | ||
79 | Chunks/s: 176 KB / 65536 = ~3 chunks / s | ||
80 | |||
81 | WRITE_THRESHOLD: 30 | ||
82 | - Should gives us < 10s to start writing to disk before we run out | ||
83 | of buffer space.. | ||
84 | |||
85 | */ | 77 | */ |
86 | 78 | ||
87 | #define CHUNK_SIZE 65536 /* Multiple of 4 */ | 79 | #define CHUNK_SIZE 8192 /* Multiple of 4 */ |
88 | #define WRITE_THRESHOLD 30 /* Write when this many chunks (or less) until buffer full */ | 80 | #define WRITE_THRESHOLD 250 /* (2 MB) Write when this many chunks (or less) until buffer full */ |
89 | 81 | ||
90 | #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)]) | 82 | #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)]) |
91 | 83 | ||
@@ -123,8 +115,6 @@ static void pcmrec_dma_stop(void); | |||
123 | #define PCMREC_RESUME 11 | 115 | #define PCMREC_RESUME 11 |
124 | #define PCMREC_NEW_FILE 12 | 116 | #define PCMREC_NEW_FILE 12 |
125 | #define PCMREC_SET_GAIN 13 | 117 | #define PCMREC_SET_GAIN 13 |
126 | #define PCMREC_GOT_DATA 20 /* DMA1 notifies when data has arrived */ | ||
127 | |||
128 | 118 | ||
129 | /*******************************************************************/ | 119 | /*******************************************************************/ |
130 | /* Functions that are not executing in the pcmrec_thread first */ | 120 | /* Functions that are not executing in the pcmrec_thread first */ |
@@ -350,21 +340,68 @@ void audio_resume_recording(void) | |||
350 | wake_up_thread(); | 340 | wake_up_thread(); |
351 | } | 341 | } |
352 | 342 | ||
353 | 343 | void pcm_rec_get_peaks(int *left, int *right) | |
344 | { | ||
345 | if (!is_recording) | ||
346 | { | ||
347 | peak_left = 0; | ||
348 | peak_right = 0; | ||
349 | } | ||
350 | |||
351 | if (left) | ||
352 | *left = peak_left; | ||
353 | if (right) | ||
354 | *right = peak_right; | ||
355 | } | ||
354 | 356 | ||
355 | /***************************************************************************/ | 357 | /***************************************************************************/ |
356 | /* Functions that executes in the context of pcmrec_thread */ | 358 | /* Functions that executes in the context of pcmrec_thread */ |
357 | /***************************************************************************/ | 359 | /***************************************************************************/ |
358 | 360 | ||
361 | /* Skip PEAK_STRIDE sample-pairs for each compare */ | ||
362 | #define PEAK_STRIDE 3 | ||
363 | |||
364 | static void pcmrec_find_peaks(int chunk) | ||
365 | { | ||
366 | short *ptr, value; | ||
367 | int peak_l, peak_r; | ||
368 | int j; | ||
369 | |||
370 | ptr = GET_CHUNK(chunk); | ||
371 | |||
372 | peak_l = 0; | ||
373 | peak_r = 0; | ||
374 | |||
375 | for (j=0; j<CHUNK_SIZE/4; j+=PEAK_STRIDE+1) | ||
376 | { | ||
377 | if ((value = ptr[0]) > peak_l) | ||
378 | peak_l = value; | ||
379 | else if (-value > peak_l) | ||
380 | peak_l = -value; | ||
381 | ptr++; | ||
382 | |||
383 | if ((value = ptr[0]) > peak_r) | ||
384 | peak_r = value; | ||
385 | else if (-value > peak_r) | ||
386 | peak_r = -value; | ||
387 | ptr++; | ||
388 | |||
389 | ptr += PEAK_STRIDE * 2; | ||
390 | } | ||
391 | |||
392 | peak_left = peak_l; | ||
393 | peak_right = peak_r; | ||
394 | |||
395 | } | ||
396 | |||
359 | 397 | ||
360 | /** | 398 | /** |
361 | * Process the chunks using read_index and write_index. | 399 | * Process the chunks using read_index and write_index. |
362 | * | 400 | * |
363 | * DMA1 handler posts to pcmrec_queue and pcmrec_thread calls this | 401 | * This function is called when queue_get_w_tmo times out. |
364 | * function. | ||
365 | * | 402 | * |
366 | * Other function can also call this function with flush = true when | 403 | * Other functions can also call this function with flush = true when |
367 | * they want to save everything recorded sofar to disk. | 404 | * they want to save everything in the buffers to disk. |
368 | * | 405 | * |
369 | */ | 406 | */ |
370 | 407 | ||
@@ -375,12 +412,24 @@ static void pcmrec_callback(bool flush) | |||
375 | unsigned short *ptr; | 412 | unsigned short *ptr; |
376 | int i, j, w; | 413 | int i, j, w; |
377 | 414 | ||
415 | if ((!is_recording || is_paused) && !flush) | ||
416 | return; | ||
417 | |||
378 | w = write_index; | 418 | w = write_index; |
379 | 419 | ||
380 | num_new = w - read2_index; | 420 | num_new = w - read2_index; |
381 | if (num_new < 0) | 421 | if (num_new < 0) |
382 | num_new += num_chunks; | 422 | num_new += num_chunks; |
383 | 423 | ||
424 | if (num_new > 0) | ||
425 | { | ||
426 | /* Collect peak values for the last buffer only */ | ||
427 | j = w - 1; | ||
428 | if (j < 0) | ||
429 | j += num_chunks; | ||
430 | pcmrec_find_peaks(j); | ||
431 | } | ||
432 | |||
384 | for (i=0; i<num_new; i++) | 433 | for (i=0; i<num_new; i++) |
385 | { | 434 | { |
386 | /* Convert the samples to little-endian so we only have to write later | 435 | /* Convert the samples to little-endian so we only have to write later |
@@ -389,12 +438,10 @@ static void pcmrec_callback(bool flush) | |||
389 | ptr = GET_CHUNK(read2_index); | 438 | ptr = GET_CHUNK(read2_index); |
390 | for (j=0; j<CHUNK_SIZE/2; j++) | 439 | for (j=0; j<CHUNK_SIZE/2; j++) |
391 | { | 440 | { |
392 | /* TODO: might be a good place to add the peak-meter.. */ | ||
393 | |||
394 | *ptr = htole16(*ptr); | 441 | *ptr = htole16(*ptr); |
395 | ptr++; | 442 | ptr++; |
396 | } | 443 | } |
397 | 444 | ||
398 | num_rec_bytes += CHUNK_SIZE; | 445 | num_rec_bytes += CHUNK_SIZE; |
399 | 446 | ||
400 | read2_index++; | 447 | read2_index++; |
@@ -406,26 +453,8 @@ static void pcmrec_callback(bool flush) | |||
406 | if (num_ready < 0) | 453 | if (num_ready < 0) |
407 | num_ready += num_chunks; | 454 | num_ready += num_chunks; |
408 | 455 | ||
409 | if (num_ready >= num_chunks) | ||
410 | { | ||
411 | logf("num_ready overflow?"); | ||
412 | num_ready = num_chunks-1; | ||
413 | } | ||
414 | |||
415 | num_free = num_chunks - num_ready; | 456 | num_free = num_chunks - num_ready; |
416 | 457 | ||
417 | if (wav_file == -1 || (!is_recording && !flush)) | ||
418 | { | ||
419 | /* In this case we should consume the buffers to avoid */ | ||
420 | /* getting 'dma1 overrun' */ | ||
421 | |||
422 | read_index+=num_ready; | ||
423 | if (read_index >= num_chunks) | ||
424 | read_index -= num_chunks; | ||
425 | |||
426 | return; | ||
427 | } | ||
428 | |||
429 | if (num_free <= WRITE_THRESHOLD || flush) | 458 | if (num_free <= WRITE_THRESHOLD || flush) |
430 | { | 459 | { |
431 | logf("writing: %d (%d)", num_ready, flush); | 460 | logf("writing: %d (%d)", num_ready, flush); |
@@ -484,15 +513,13 @@ void DMA1(void) | |||
484 | 513 | ||
485 | DSR1 = 1; /* Clear interrupt */ | 514 | DSR1 = 1; /* Clear interrupt */ |
486 | 515 | ||
487 | int_count++; | ||
488 | |||
489 | if (res & 0x70) | 516 | if (res & 0x70) |
490 | { | 517 | { |
491 | DCR1 = 0; /* Stop DMA transfer */ | 518 | DCR1 = 0; /* Stop DMA transfer */ |
492 | error_count++; | 519 | error_count++; |
493 | is_recording = false; | 520 | is_recording = false; |
494 | 521 | ||
495 | logf("dma1 err 0x%x", res); | 522 | logf("dma1 err: 0x%x", res); |
496 | 523 | ||
497 | /* Flush recorded data to disk and stop recording */ | 524 | /* Flush recorded data to disk and stop recording */ |
498 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | 525 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); |
@@ -521,9 +548,6 @@ void DMA1(void) | |||
521 | { | 548 | { |
522 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ | 549 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ |
523 | BCR1 = CHUNK_SIZE; | 550 | BCR1 = CHUNK_SIZE; |
524 | |||
525 | queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL); | ||
526 | |||
527 | } | 551 | } |
528 | } | 552 | } |
529 | 553 | ||
@@ -603,6 +627,9 @@ static void pcmrec_start(void) | |||
603 | return; | 627 | return; |
604 | } | 628 | } |
605 | 629 | ||
630 | peak_left = 0; | ||
631 | peak_right = 0; | ||
632 | |||
606 | num_rec_bytes = 0; | 633 | num_rec_bytes = 0; |
607 | num_file_bytes = 0; | 634 | num_file_bytes = 0; |
608 | record_start_time = current_tick; | 635 | record_start_time = current_tick; |
@@ -761,12 +788,14 @@ static void pcmrec_init(void) | |||
761 | { | 788 | { |
762 | unsigned long buffer_size; | 789 | unsigned long buffer_size; |
763 | 790 | ||
764 | show_waveform = 0; | ||
765 | wav_file = -1; | 791 | wav_file = -1; |
766 | read_index = 0; | 792 | read_index = 0; |
767 | read2_index = 0; | 793 | read2_index = 0; |
768 | write_index = 0; | 794 | write_index = 0; |
769 | 795 | ||
796 | peak_left = 0; | ||
797 | peak_right = 0; | ||
798 | |||
770 | num_rec_bytes = 0; | 799 | num_rec_bytes = 0; |
771 | num_file_bytes = 0; | 800 | num_file_bytes = 0; |
772 | record_start_time = 0; | 801 | record_start_time = 0; |
@@ -819,12 +848,11 @@ static void pcmrec_thread(void) | |||
819 | 848 | ||
820 | logf("thread pcmrec start"); | 849 | logf("thread pcmrec start"); |
821 | 850 | ||
822 | int_count = 0; | ||
823 | error_count = 0; | 851 | error_count = 0; |
824 | 852 | ||
825 | while (1) | 853 | while (1) |
826 | { | 854 | { |
827 | queue_wait(&pcmrec_queue, &ev); | 855 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 40); |
828 | 856 | ||
829 | switch (ev.id) | 857 | switch (ev.id) |
830 | { | 858 | { |
@@ -856,8 +884,7 @@ static void pcmrec_thread(void) | |||
856 | pcmrec_new_file(); | 884 | pcmrec_new_file(); |
857 | break; | 885 | break; |
858 | 886 | ||
859 | /* Notification by DMA interrupt */ | 887 | case SYS_TIMEOUT: |
860 | case PCMREC_GOT_DATA: | ||
861 | pcmrec_callback(false); | 888 | pcmrec_callback(false); |
862 | break; | 889 | break; |
863 | 890 | ||