Fix 64bit warnings.
[Rockbox.git] / firmware / pcm_record.c
blob8805e7315773335fcec8764fa4743a9af1d550d0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include "debug.h"
22 #include "panic.h"
23 #include "thread.h"
25 #include <kernel.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <string.h>
31 #include "cpu.h"
32 #include "i2c.h"
33 #include "uda1380.h"
34 #include "system.h"
35 #include "usb.h"
37 #include "buffer.h"
38 #include "audio.h"
39 #include "button.h"
40 #include "file.h"
41 #include "sprintf.h"
42 #include "logf.h"
43 #include "button.h"
44 #include "lcd.h"
45 #include "lcd-remote.h"
46 #include "pcm_playback.h"
47 #include "pcm_record.h"
50 /***************************************************************************/
52 static volatile bool is_recording; /* We are recording */
53 static volatile bool is_stopping; /* Are we going to stop */
54 static volatile bool is_paused; /* We have paused */
55 static volatile bool is_error; /* An error has occured */
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 */
59 static volatile int error_count; /* Number of DMA errors */
61 static long record_start_time; /* Value of current_tick when recording was started */
62 static long pause_start_time; /* Value of current_tick when pause was started */
63 static volatile int buffered_chunks; /* number of valid chunks in buffer */
65 static int wav_file;
66 static char recording_filename[MAX_PATH];
68 static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done;
70 static short peak_left, peak_right;
72 /***************************************************************************/
75 Some estimates:
76 Normal recording rate: 44100 HZ * 4 = 176 KB/s
77 Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk
80 #define CHUNK_SIZE 8192 /* Multiple of 4 */
81 #define WRITE_THRESHOLD 250 /* (2 MB) Write when this many chunks (or less) until buffer full */
83 #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)])
85 static unsigned char *rec_buffer; /* Circular recording buffer */
86 static int num_chunks; /* Number of chunks available in rec_buffer */
89 /*
90 Overrun occures when DMA needs to write a new chunk and write_index == read_index
91 Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk
92 more often.
95 static volatile int write_index; /* Current chunk the DMA is writing to */
96 static volatile int read_index; /* Oldest chunk that is not written to disk */
97 static volatile int read2_index; /* Latest chunk that has not been converted to little endian */
98 static long pre_record_ticks; /* pre-record time expressed in ticks */
99 static int pre_record_chunks; /* pre-record time expressed in chunks */
101 /***************************************************************************/
103 static struct event_queue pcmrec_queue;
104 static long pcmrec_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
105 static const char pcmrec_thread_name[] = "pcmrec";
107 static void pcmrec_thread(void);
108 static void pcmrec_dma_start(void);
109 static void pcmrec_dma_stop(void);
111 /* Event IDs */
112 #define PCMREC_INIT 1 /* Enable recording */
113 #define PCMREC_CLOSE 2
115 #define PCMREC_START 3 /* Start a new recording */
116 #define PCMREC_STOP 4 /* Stop the current recording */
117 #define PCMREC_PAUSE 10
118 #define PCMREC_RESUME 11
119 #define PCMREC_NEW_FILE 12
120 #define PCMREC_SET_GAIN 13
122 /*******************************************************************/
123 /* Functions that are not executing in the pcmrec_thread first */
124 /*******************************************************************/
126 /* Creates pcmrec_thread */
127 void pcm_rec_init(void)
129 queue_init(&pcmrec_queue);
130 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name);
134 /* Initializes recording:
135 * - Set up the UDA1380 for recording
136 * - Prepare for DMA transfers
139 void audio_init_recording(void)
141 init_done = false;
142 queue_post(&pcmrec_queue, PCMREC_INIT, 0);
144 while(!init_done)
145 sleep_thread();
146 wake_up_thread();
149 void audio_close_recording(void)
151 close_done = false;
152 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
154 while(!close_done)
155 sleep_thread();
156 wake_up_thread();
159 unsigned long pcm_rec_status(void)
161 unsigned long ret = 0;
163 if (is_recording)
164 ret |= AUDIO_STATUS_RECORD;
165 if (is_paused)
166 ret |= AUDIO_STATUS_PAUSE;
167 if (is_error)
168 ret |= AUDIO_STATUS_ERROR;
170 return ret;
173 unsigned long audio_recorded_time(void)
175 if (is_recording)
177 if (is_paused)
178 return pause_start_time - record_start_time;
179 else
180 return current_tick - record_start_time;
183 return 0;
186 unsigned long audio_num_recorded_bytes(void)
188 if (is_recording)
189 return num_rec_bytes;
191 return 0;
196 * Sets the audio source
198 * This functions starts feeding the CPU with audio data over the I2S bus
200 * @param source 0=mic, 1=line-in, (todo: 2=spdif)
202 void audio_set_recording_options(int frequency, int quality,
203 int source, int channel_mode,
204 bool editable, int prerecord_time)
206 /* TODO: */
207 (void)frequency;
208 (void)quality;
209 (void)channel_mode;
210 (void)editable;
212 /* WARNING: calculation below uses fixed frequency! */
213 pre_record_ticks = prerecord_time * HZ;
214 pre_record_chunks = ((44100 * prerecord_time * 4)/CHUNK_SIZE)+1;
215 if(pre_record_chunks >= (num_chunks-250))
217 /* we can't prerecord more than our buffersize minus treshold to write to disk! */
218 pre_record_chunks = num_chunks-250;
219 /* don't forget to recalculate that time! */
220 pre_record_ticks = ((pre_record_chunks * CHUNK_SIZE)/(4*44100)) * HZ;
223 //logf("pcmrec: src=%d", source);
225 switch (source)
227 /* mic */
228 case 0:
229 uda1380_enable_recording(true);
230 break;
232 /* line-in */
233 case 1:
234 uda1380_enable_recording(false);
235 break;
238 uda1380_set_monitor(true);
243 * Note that microphone is mono, only left value is used
244 * See uda1380_set_recvol() for exact ranges.
246 * @param type 0=line-in (radio), 1=mic, 2=ADC
249 void audio_set_recording_gain(int left, int right, int type)
251 //logf("rcmrec: t=%d l=%d r=%d", type, left, right);
252 uda1380_set_recvol(left, right, type);
257 * Start recording
259 * Use audio_set_recording_options first to select recording options
261 void audio_record(const char *filename)
263 if (is_recording)
265 logf("record while recording");
266 return;
269 strncpy(recording_filename, filename, MAX_PATH - 1);
270 recording_filename[MAX_PATH - 1] = 0;
272 record_done = false;
273 queue_post(&pcmrec_queue, PCMREC_START, 0);
275 while(!record_done)
276 sleep_thread();
277 wake_up_thread();
281 void audio_new_file(const char *filename)
283 logf("pcm_new_file");
285 new_file_done = false;
287 strncpy(recording_filename, filename, MAX_PATH - 1);
288 recording_filename[MAX_PATH - 1] = 0;
290 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
292 while(!new_file_done)
293 sleep_thread();
294 wake_up_thread();
296 logf("pcm_new_file done");
302 void audio_stop_recording(void)
304 if (!is_recording)
305 return;
307 logf("pcm_stop");
309 stop_done = false;
310 queue_post(&pcmrec_queue, PCMREC_STOP, 0);
312 while(!stop_done)
313 sleep_thread();
314 wake_up_thread();
316 logf("pcm_stop done");
319 void audio_pause_recording(void)
321 if (!is_recording)
323 logf("pause when not recording");
324 return;
326 if (is_paused)
328 logf("pause when paused");
329 return;
332 pause_done = false;
333 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
335 while(!pause_done)
336 sleep_thread();
337 wake_up_thread();
340 void audio_resume_recording(void)
342 if (!is_paused)
344 logf("resume when not paused");
345 return;
348 resume_done = false;
349 queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
351 while(!resume_done)
352 sleep_thread();
353 wake_up_thread();
356 /* return peaks as int, so convert from short first
357 note that peak values are always positive */
358 void pcm_rec_get_peaks(int *left, int *right)
360 if (left)
361 *left = (int)peak_left;
362 if (right)
363 *right = (int)peak_right;
364 peak_left = 0;
365 peak_right = 0;
368 /***************************************************************************/
369 /* Functions that executes in the context of pcmrec_thread */
370 /***************************************************************************/
373 * Process the chunks using read_index and write_index.
375 * This function is called when queue_get_w_tmo times out.
377 * Other functions can also call this function with flush = true when
378 * they want to save everything in the buffers to disk.
382 static void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
383 static void pcmrec_callback(bool flush)
385 int num_ready, num_free, num_new;
386 short *ptr;
387 short value;
388 int i, j, w;
390 w = write_index;
392 num_new = w - read2_index;
393 if (num_new < 0)
394 num_new += num_chunks;
396 for (i=0; i<num_new; i++)
398 /* Convert the samples to little-endian so we only have to write later
399 (Less hd-spinning time), also do peak detection while we're at it
401 ptr = GET_CHUNK(read2_index);
402 for (j=0; j<CHUNK_SIZE/4; j++)
404 value = *ptr;
405 if(value > peak_left)
406 peak_left = value;
407 else if (-value > peak_left)
408 peak_left = -value;
410 *ptr = htole16(value);
411 ptr++;
413 value = *ptr;
414 if(value > peak_right)
415 peak_right = value;
416 else if (-value > peak_right)
417 peak_right = -value;
419 *ptr = htole16(value);
420 ptr++;
423 if(is_recording && !is_paused)
424 num_rec_bytes += CHUNK_SIZE;
426 read2_index++;
427 if (read2_index >= num_chunks)
428 read2_index = 0;
431 if ((!is_recording || is_paused) && !flush)
433 /* not recording = no saving to disk, fake buffer clearing */
434 read_index = write_index;
435 return;
438 num_ready = w - read_index;
439 if (num_ready < 0)
440 num_ready += num_chunks;
442 num_free = num_chunks - num_ready;
444 if (num_free <= WRITE_THRESHOLD || flush)
446 logf("writing: %d (%d)", num_ready, flush);
448 for (i=0; i<num_ready; i++)
450 if (write(wav_file, GET_CHUNK(read_index), CHUNK_SIZE) != CHUNK_SIZE)
452 logf("pcmrec: write err");
453 pcmrec_dma_stop();
454 return;
457 num_file_bytes += CHUNK_SIZE;
459 read_index++;
460 if (read_index >= num_chunks)
461 read_index = 0;
462 yield();
465 /* sync file */
466 fsync(wav_file);
468 logf("done");
472 /* Abort dma transfer */
473 static void pcmrec_dma_stop(void)
475 DCR1 = 0;
477 is_error = true;
478 is_recording = false;
480 error_count++;
482 logf("dma1 stopped");
485 static void pcmrec_dma_start(void)
487 DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
488 SAR1 = (unsigned long)&PDIR2; /* Source address */
489 BCR1 = CHUNK_SIZE; /* Bytes to transfer */
491 /* Start the DMA transfer.. */
492 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START;
494 /* pre-recording: buffer count */
495 buffered_chunks = 0;
497 logf("dma1 started");
501 /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */
502 void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
503 void DMA1(void)
505 int res = DSR1;
507 DSR1 = 1; /* Clear interrupt */
509 if (res & 0x70)
511 DCR1 = 0; /* Stop DMA transfer */
512 error_count++;
513 is_recording = false;
515 logf("dma1 err: 0x%x", res);
517 /* Flush recorded data to disk and stop recording */
518 queue_post(&pcmrec_queue, PCMREC_STOP, NULL);
520 } else
522 write_index++;
523 if (write_index >= num_chunks)
524 write_index = 0;
526 /* update number of valid chunks for pre-recording */
527 if(buffered_chunks < num_chunks)
528 buffered_chunks++;
530 if (is_stopping)
532 DCR1 = 0; /* Stop DMA transfer */
533 is_stopping = false;
535 logf("dma1 stopping");
537 } else if (write_index == read_index)
539 DCR1 = 0; /* Stop DMA transfer */
540 is_recording = false;
542 logf("dma1 overrun");
544 } else
546 DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
547 BCR1 = CHUNK_SIZE;
551 IPR |= (1<<15); /* Clear pending interrupt request */
554 /* Create WAVE file and write header */
555 /* Sets returns 0 if success, -1 on failure */
556 static int start_wave(void)
558 unsigned char header[44] =
560 'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',
561 0x10,0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,
562 4,0,0x10,0,'d','a','t','a',0,0,0,0
565 wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC);
566 if (wav_file < 0)
568 wav_file = -1;
569 logf("rec: create failed: %d", wav_file);
570 is_error = true;
571 return -1;
574 if (sizeof(header) != write(wav_file, header, sizeof(header)))
576 close(wav_file);
577 wav_file = -1;
578 logf("rec: write failed");
579 is_error = true;
580 return -1;
583 return 0;
586 /* Update header and set correct length values */
587 static void close_wave(void)
589 long l;
591 if (wav_file != -1)
593 l = htole32(num_file_bytes + 36);
594 lseek(wav_file, 4, SEEK_SET);
595 write(wav_file, &l, 4);
597 l = htole32(num_file_bytes);
598 lseek(wav_file, 40, SEEK_SET);
599 write(wav_file, &l, 4);
601 close(wav_file);
602 wav_file = -1;
606 static void pcmrec_start(void)
608 int pre_chunks = pre_record_chunks; /* recalculate every time! */
609 long pre_ticks = pre_record_ticks; /* recalculate every time! */
611 logf("pcmrec_start");
613 if (is_recording)
615 logf("already recording");
616 record_done = true;
617 return;
620 if (wav_file != -1)
621 close(wav_file);
623 if (start_wave() != 0)
625 /* failed to create the file */
626 record_done = true;
627 return;
630 /* pre-recording calculation */
631 if(buffered_chunks < pre_chunks)
633 /* not enough good chunks available - limit pre-record time */
634 pre_chunks = buffered_chunks;
635 pre_ticks = ((buffered_chunks * CHUNK_SIZE)/(4*44100)) * HZ;
637 record_start_time = current_tick - pre_ticks;
639 read_index = write_index - pre_chunks;
640 if(read_index < 0)
642 read_index += num_chunks;
645 peak_left = 0;
646 peak_right = 0;
648 num_rec_bytes = pre_chunks * CHUNK_SIZE;
649 num_file_bytes = 0;
650 pause_start_time = 0;
652 is_stopping = false;
653 is_paused = false;
654 is_recording = true;
656 record_done = true;
659 static void pcmrec_stop(void)
661 logf("pcmrec_stop");
663 if (!is_recording)
665 stop_done = true;
666 return;
669 if (!is_paused)
671 /* wait for recording to finish */
672 is_stopping = true;
674 while (is_stopping && is_recording)
675 sleep_thread();
676 wake_up_thread();
678 is_stopping = false;
681 is_recording = false;
683 /* Flush buffers to file */
684 pcmrec_callback(true);
686 close_wave();
688 stop_done = true;
690 /* Finally start dma again for peakmeters and pre-recoding to work. */
691 pcmrec_dma_start();
693 logf("pcmrec_stop done");
696 static void pcmrec_new_file(void)
698 logf("pcmrec_new_file");
700 if (!is_recording)
702 logf("not recording");
703 new_file_done = true;
704 return;
707 /* Since pcmrec_callback() blocks until the data has been written,
708 here is a good approximation when recording to the new file starts
710 record_start_time = current_tick;
711 num_rec_bytes = 0;
713 if (is_paused)
714 pause_start_time = record_start_time;
716 /* Flush what we got in buffers to file */
717 pcmrec_callback(true);
719 close_wave();
721 num_file_bytes = 0;
723 /* start the new file */
724 if (start_wave() != 0)
726 logf("new_file failed");
727 pcmrec_stop();
730 new_file_done = true;
731 logf("pcmrec_new_file done");
734 static void pcmrec_pause(void)
736 logf("pcmrec_pause");
738 if (!is_recording)
740 logf("pause: not recording");
741 pause_done = true;
742 return;
745 /* Abort DMA transfer and flush to file? */
747 is_stopping = true;
749 while (is_stopping && is_recording)
750 sleep_thread();
751 wake_up_thread();
753 pause_start_time = current_tick;
754 is_paused = true;
756 /* Flush what we got in buffers to file */
757 pcmrec_callback(true);
759 pause_done = true;
761 logf("pcmrec_pause done");
765 static void pcmrec_resume(void)
767 logf("pcmrec_resume");
769 if (!is_paused)
771 logf("resume: not paused");
772 resume_done = true;
773 return;
776 is_paused = false;
777 is_recording = true;
779 /* Compensate for the time we have been paused */
780 if (pause_start_time)
782 record_start_time += current_tick - pause_start_time;
783 pause_start_time = 0;
786 pcmrec_dma_start();
788 resume_done = true;
790 logf("pcmrec_resume done");
795 * audio_init_recording calls this function using PCMREC_INIT
798 static void pcmrec_init(void)
800 unsigned long buffer_size;
802 wav_file = -1;
803 read_index = 0;
804 read2_index = 0;
805 write_index = 0;
806 pre_record_chunks = 0;
807 pre_record_ticks = 0;
809 peak_left = 0;
810 peak_right = 0;
812 num_rec_bytes = 0;
813 num_file_bytes = 0;
814 record_start_time = 0;
815 pause_start_time = 0;
816 buffered_chunks = 0;
818 is_recording = false;
819 is_stopping = false;
820 is_paused = false;
821 is_error = false;
823 rec_buffer = (unsigned char*)(((unsigned long)audiobuf) & ~3);
824 buffer_size = (long)audiobufend - (long)audiobuf - 16;
826 logf("buf size: %d kb", buffer_size/1024);
828 num_chunks = buffer_size / CHUNK_SIZE;
830 logf("num_chunks: %d", num_chunks);
832 IIS1CONFIG = 0x800; /* Stop any playback */
833 AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
834 DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */
835 DATAINCONTROL |= 0x20; /* PDIR2 source = IIS1recv */
837 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
838 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
839 DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2;
840 ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */
841 IMR &= ~(1<<15); /* bit 15 is DMA1 */
843 pcmrec_dma_start();
845 init_done = 1;
848 static void pcmrec_close(void)
850 uda1380_disable_recording();
852 DMAROUTE = (DMAROUTE & 0xffff00ff);
853 ICR7 = 0x00; /* Disable interrupt */
854 IMR |= (1<<15); /* bit 15 is DMA1 */
856 close_done = true;
859 static void pcmrec_thread(void)
861 struct event ev;
863 logf("thread pcmrec start");
865 error_count = 0;
867 while (1)
869 queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 40);
871 switch (ev.id)
873 case PCMREC_INIT:
874 pcmrec_init();
875 break;
877 case PCMREC_CLOSE:
878 pcmrec_close();
879 break;
881 case PCMREC_START:
882 pcmrec_start();
883 break;
885 case PCMREC_STOP:
886 pcmrec_stop();
887 break;
889 case PCMREC_PAUSE:
890 pcmrec_pause();
891 break;
893 case PCMREC_RESUME:
894 pcmrec_resume();
895 break;
897 case PCMREC_NEW_FILE:
898 pcmrec_new_file();
899 break;
901 case SYS_TIMEOUT:
902 pcmrec_callback(false);
903 break;
905 case SYS_USB_CONNECTED:
906 if (!is_recording && !is_stopping)
908 usb_acknowledge(SYS_USB_CONNECTED_ACK);
909 usb_wait_for_disconnect(&pcmrec_queue);
911 break;
915 logf("thread pcmrec done");
918 /* Select VINL & VINR source: 0=Line-in, 1=FM Radio */
919 void pcm_rec_mux(int source)
921 #ifdef IRIVER_H300_SERIES
922 if(source == 0)
923 and_l(~0x40000000, &GPIO_OUT); /* Line In */
924 else
925 or_l(0x40000000, &GPIO_OUT); /* FM radio */
927 or_l(0x40000000, &GPIO_ENABLE);
928 or_l(0x40000000, &GPIO_FUNCTION);
929 #else
930 if(source == 0)
931 and_l(~0x00800000, &GPIO_OUT); /* Line In */
932 else
933 or_l(0x00800000, &GPIO_OUT); /* FM radio */
935 or_l(0x00800000, &GPIO_ENABLE);
936 or_l(0x00800000, &GPIO_FUNCTION);
937 #endif