summaryrefslogtreecommitdiff
path: root/firmware/pcm_record.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/pcm_record.c')
-rw-r--r--firmware/pcm_record.c135
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
57static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ 57static volatile unsigned long num_rec_bytes; /* Num bytes recorded */
58static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ 58static volatile unsigned long num_file_bytes; /* Num bytes written to current file */
59static volatile int int_count; /* Number of DMA completed interrupts */
60static volatile int error_count; /* Number of DMA errors */ 59static volatile int error_count; /* Number of DMA errors */
61 60
62static unsigned long record_start_time; /* Value of current_tick when recording was started */ 61static unsigned long record_start_time; /* Value of current_tick when recording was started */
63static unsigned long pause_start_time; /* Value of current_tick when pause was started */ 62static unsigned long pause_start_time; /* Value of current_tick when pause was started */
64 63
65static bool show_waveform;
66
67static int wav_file; 64static int wav_file;
68static char recording_filename[MAX_PATH]; 65static char recording_filename[MAX_PATH];
69 66
70static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; 67static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done;
68
69static 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 343void 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
364static 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