Fix channel-swapping bug in iriver recordings. Left and Right channels should now...
[Rockbox.git] / firmware / pcm_record.c
blob8480864513e16d3311961506fea6cd15041b10a7
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 #if defined(HAVE_UDA1380)
34 #include "uda1380.h"
35 #elif defined(HAVE_TLV320)
36 #include "tlv320.h"
37 #endif
38 #include "system.h"
39 #include "usb.h"
41 #include "buffer.h"
42 #include "audio.h"
43 #include "button.h"
44 #include "file.h"
45 #include "sprintf.h"
46 #include "logf.h"
47 #include "button.h"
48 #include "lcd.h"
49 #include "lcd-remote.h"
50 #include "pcm_playback.h"
51 #include "pcm_record.h"
54 /***************************************************************************/
56 static volatile bool is_recording; /* We are recording */
57 static volatile bool is_stopping; /* Are we going to stop */
58 static volatile bool is_paused; /* We have paused */
60 static volatile int num_rec_bytes;
61 static volatile int int_count; /* Number of DMA completed interrupts */
62 static volatile int error_count; /* Number of DMA errors */
64 static unsigned long record_start_time; /* Value of current_tick when recording was started */
65 static unsigned long pause_start_time; /* Value of current_tick when pause was started */
67 static int rec_gain, rec_volume;
68 static bool show_waveform;
69 static int init_done = 0;
70 static int wav_file;
71 static char recording_filename[MAX_PATH];
73 /***************************************************************************/
76 Some estimates:
77 44100 HZ * 4 = 176400 bytes/s
78 Refresh LCD 10 HZ = 176400 / 10 = 17640 bytes ~=~ 1024*16 bytes
80 If NUM_BUFFERS is 80 we can hold ~8 sec of data in memory
81 ALL_BUFFER_SIZE will be 1024*16 * 80 = 1310720 bytes
84 #define NUM_BUFFERS 80
85 #define EACH_BUFFER_SIZE (1024*16) /* Multiple of 4. Use small value to get responsive waveform */
86 #define ALL_BUFFERS_SIZE (NUM_BUFFERS * EACH_BUFFER_SIZE)
88 #define WRITE_THRESHOLD 40 /* Minimum number of buffers before write to file */
90 static unsigned char *rec_buffers[NUM_BUFFERS];
92 /*
93 Overrun occures when DMA needs to write a new buffer and write_index == read_index
94 Solution to this is to optimize pcmrec_callback, use cpu_boost somewhere or increase
95 the total buffer size (or WRITE_THRESHOLD)
98 static int write_index; /* Which buffer the DMA is currently recording */
99 static int read_index; /* The oldest buffer that the pcmrec_callback has not read */
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);
109 /* Event IDs */
110 #define PCMREC_OPEN 1 /* Enable recording */
111 #define PCMREC_CLOSE 2 /* Disable recording */
112 #define PCMREC_START 3 /* Start a new recording */
113 #define PCMREC_STOP 4 /* Stop the current recording */
114 #define PCMREC_PAUSE 10
115 #define PCMREC_RESUME 11
116 #define PCMREC_NEW_FILE 12
117 #define PCMREC_SET_GAIN 13
118 #define PCMREC_GOT_DATA 20 /* DMA1 notifies when data has arrived */
121 /*******************************************************************/
122 /* Functions that are not executing in the pcmrec_thread first */
123 /*******************************************************************/
125 void pcm_init_recording(void)
127 int_count = 0;
128 error_count = 0;
130 show_waveform = 0;
131 is_recording = 0;
132 is_stopping = 0;
133 num_rec_bytes = 0;
134 wav_file = -1;
135 read_index = 0;
136 write_index = 0;
138 queue_init(&pcmrec_queue);
139 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name);
142 void pcm_open_recording(void)
144 init_done = 0;
146 logf("pcm_open_rec");
148 queue_post(&pcmrec_queue, PCMREC_OPEN, 0);
150 while (init_done)
152 sleep(HZ >> 8);
155 logf("pcm_open_rec done");
158 void pcm_close_recording(void)
160 /* todo: synchronize completion with pcmrec thread */
161 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
166 unsigned long pcm_status(void)
168 unsigned long ret = 0;
170 if (is_recording)
171 ret |= AUDIO_STATUS_RECORD;
173 return ret;
178 void pcm_new_file(const char *filename)
180 /* todo */
181 filename = filename;
185 unsigned long pcm_recorded_time(void)
187 if (is_recording)
189 if(is_paused)
190 return pause_start_time - record_start_time;
191 else
192 return current_tick - record_start_time;
195 return 0;
198 unsigned long pcm_num_recorded_bytes(void)
201 if (is_recording)
203 return num_rec_bytes;
205 else
206 return 0;
209 void pcm_pause_recording(void)
211 /* todo */
214 void pcm_resume_recording(void)
216 /* todo */
221 * Sets the audio source
223 * Side effect: This functions starts feeding the CPU with audio data over the I2S bus
225 * @param source 0=line-in, 1=mic
227 void pcm_set_recording_options(int source, bool enable_waveform)
229 #if defined(HAVE_UDA1380)
230 uda1380_enable_recording(source);
231 #elif defined(HAVE_TLV320)
232 tlv320_enable_recording(source);
233 #endif
234 show_waveform = enable_waveform;
240 * @param gain line-in and microphone gain (0-15)
241 * @param volume ADC volume (0-255)
243 void pcm_set_recording_gain(int gain, int volume)
245 rec_gain = gain;
246 rec_volume = volume;
248 queue_post(&pcmrec_queue, PCMREC_SET_GAIN, 0);
252 * Start recording
254 * Use pcm_set_recording_options before calling record
256 void pcm_record(const char *filename)
258 strncpy(recording_filename, filename, MAX_PATH - 1);
259 recording_filename[MAX_PATH - 1] = 0;
261 queue_post(&pcmrec_queue, PCMREC_START, 0);
267 void pcm_stop_recording(void)
269 if (is_recording)
270 is_stopping = 1;
272 queue_post(&pcmrec_queue, PCMREC_STOP, 0);
274 logf("pcm_stop_recording");
276 while (is_stopping)
278 sleep(HZ >> 4);
281 logf("pcm_stop_recording done");
285 /***************************************************************************/
286 /* Functions that executes in the context of pcmrec_thread */
287 /***************************************************************************/
291 * Process the buffers using read_index and write_index.
293 * DMA1 handler posts to pcmrec_queue so that pcmrec_thread calls this
294 * function. Also pcmrec_stop will call this function when the recording
295 * is stopping, and that call will have flush = true.
299 void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
300 void pcmrec_callback(bool flush)
302 int num_ready;
304 num_ready = write_index - read_index;
305 if (num_ready < 0)
306 num_ready += NUM_BUFFERS;
308 /* we can consume up to num_ready buffers */
310 #ifdef HAVE_REMOTE_LCD
311 /* Draw waveform on remote LCD */
312 if (show_waveform && num_ready>0)
314 short *buf;
315 long x,y,offset;
316 int show_index;
318 /* Just display the last buffer (most recent one) */
319 show_index = read_index + num_ready - 1;
320 buf = (short*)rec_buffers[show_index];
322 lcd_remote_clear_display();
324 offset = 0;
325 for (x=0; x<LCD_REMOTE_WIDTH-1; x++)
327 y = buf[offset] * (LCD_REMOTE_HEIGHT / 2) *5; /* The 5 is just 'zooming' */
328 y = y >> 15; /* Divide with SHRT_MAX */
329 y += LCD_REMOTE_HEIGHT/2;
331 if (y < 2) y=2;
332 if (y >= LCD_REMOTE_HEIGHT-2) y = LCD_REMOTE_HEIGHT-2;
334 lcd_remote_drawpixel(x,y);
336 offset += (EACH_BUFFER_SIZE/2) / LCD_REMOTE_WIDTH;
339 lcd_remote_update();
342 #endif
344 /* Note: This might be a good place to call the 'codec' later */
346 /* Check that we have the minimum amount of data to save or */
347 /* that if it's closing time which mean we have to save.. */
348 if (wav_file != -1)
350 if (num_ready >= WRITE_THRESHOLD || flush)
352 unsigned short *ptr = (unsigned short*)rec_buffers[read_index];
353 int i;
355 for (i=0; i<EACH_BUFFER_SIZE * num_ready / 2; i++)
357 *ptr = htole16(*ptr);
358 ptr++;
361 write(wav_file, rec_buffers[read_index], EACH_BUFFER_SIZE * num_ready);
363 read_index+=num_ready;
364 if (read_index >= NUM_BUFFERS)
365 read_index -= NUM_BUFFERS;
368 } else
370 /* In this case we must consume the buffers otherwise we will */
371 /* get 'dma1 overrun' pretty fast */
373 read_index+=num_ready;
374 if (read_index >= NUM_BUFFERS)
375 read_index -= NUM_BUFFERS;
380 void pcmrec_dma_start(void)
382 DAR1 = (unsigned long)rec_buffers[write_index++]; /* Destination address */
383 SAR1 = (unsigned long)&PDIR2; /* Source address */
384 BCR1 = EACH_BUFFER_SIZE; /* Bytes to transfer */
386 /* Start the DMA transfer.. */
387 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START;
389 logf("dma1 started");
393 /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */
394 void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
395 void DMA1(void)
397 int res = DSR1;
399 DSR1 = 1; /* Clear interrupt */
401 int_count++;
403 if (res & 0x70)
405 DCR1 = 0; /* Stop DMA transfer */
406 error_count++;
407 is_recording = 0;
409 logf("dma1 err 0x%x", res);
411 } else
413 num_rec_bytes += EACH_BUFFER_SIZE;
415 write_index++;
416 if (write_index >= NUM_BUFFERS)
417 write_index = 0;
419 if (is_stopping || !is_recording)
421 DCR1 = 0; /* Stop DMA transfer */
422 is_recording = 0;
424 logf("dma1 stopping");
426 } else if (write_index == read_index)
428 DCR1 = 0; /* Stop DMA transfer */
429 is_recording = 0;
431 logf("dma1 overrun");
433 } else
435 DAR1 = (unsigned long)rec_buffers[write_index]; /* Destination address */
436 BCR1 = EACH_BUFFER_SIZE;
438 queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL);
443 IPR |= (1<<15); /* Clear pending interrupt request */
446 static int start_wave(void)
448 unsigned char header[44] =
450 'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',
451 0x10,0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,
452 4,0,0x10,0,'d','a','t','a',0,0,0,0
455 wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC);
456 if (wav_file < 0)
458 wav_file = -1;
459 logf("create failed: %d", wav_file);
460 return -1;
463 if (sizeof(header) != write(wav_file, header, sizeof(header)))
465 close(wav_file);
466 wav_file = -1;
467 logf("write failed");
468 return -2;
471 return 0;
474 /* Update header and set correct length values */
475 static void close_wave(void)
477 long l;
479 l = htole32(num_rec_bytes + 36);
480 lseek(wav_file, 4, SEEK_SET);
481 write(wav_file, &l, 4);
483 l = htole32(num_rec_bytes);
484 lseek(wav_file, 40, SEEK_SET);
485 write(wav_file, &l, 4);
487 close(wav_file);
488 wav_file = -1;
491 static void pcmrec_start(void)
493 logf("pcmrec_start");
495 if (is_recording)
496 return;
498 if (wav_file != -1)
499 close(wav_file);
501 logf("rec: %s", recording_filename);
503 start_wave(); /* todo: send signal to pcm_record if we have failed */
505 num_rec_bytes = 0;
507 /* Store the current time */
508 record_start_time = current_tick;
510 write_index = 0;
511 read_index = 0;
513 is_stopping = 0;
514 is_paused = 0;
515 is_recording = 1;
517 pcmrec_dma_start();
521 static void pcmrec_stop(void)
523 /* wait for recording to finish */
525 /* todo: Abort current DMA transfer using DCR1.. */
527 logf("pcmrec_stop");
529 while (is_recording)
531 sleep(HZ >> 4);
534 logf("pcmrec_stop done");
536 /* Write unfinished buffers to file */
537 pcmrec_callback(true);
539 close_wave();
541 is_stopping = 0;
544 static void pcmrec_open(void)
546 unsigned long buffer_start;
547 int i;
549 show_waveform = 0;
550 is_recording = 0;
551 is_stopping = 0;
552 num_rec_bytes = 0;
553 wav_file = -1;
554 read_index = 0;
555 write_index = 0;
557 buffer_start = (unsigned long)(&audiobuf[(audiobufend - audiobuf) - (ALL_BUFFERS_SIZE + 16)]);
558 buffer_start &= ~3;
560 for (i=0; i<NUM_BUFFERS; i++)
562 rec_buffers[i] = (unsigned char*)(buffer_start + EACH_BUFFER_SIZE * i);
565 IIS1CONFIG = 0x800; /* Stop any playback */
566 AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
567 DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */
568 DATAINCONTROL |= 0x20; /* PDIR2 source = IIS1recv */
570 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
571 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
572 DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2;
573 ICR4 = (ICR4 & 0xffffff00) | 0x0000001c; /* Enable interrupt at level 7, priority 0 */
574 IMR &= ~(1<<15); /* bit 15 is DMA1 */
576 init_done = 1;
579 static void pcmrec_close(void)
581 #if defined(HAVE_UDA1380)
582 uda1380_disable_recording();
583 #elif defined(HAVE_TLV320)
584 tlv320_disable_recording();
585 #endif
587 DMAROUTE = (DMAROUTE & 0xffff00ff);
588 ICR4 = (ICR4 & 0xffffff00); /* Disable interrupt */
589 IMR |= (1<<15); /* bit 15 is DMA1 */
593 static void pcmrec_thread(void)
595 struct event ev;
597 logf("thread pcmrec start");
599 while (1)
601 queue_wait(&pcmrec_queue, &ev);
603 switch (ev.id)
605 case PCMREC_OPEN:
606 pcmrec_open();
607 break;
609 case PCMREC_CLOSE:
610 pcmrec_close();
611 break;
613 case PCMREC_START:
614 pcmrec_start();
615 break;
617 case PCMREC_STOP:
618 pcmrec_stop();
619 break;
621 case PCMREC_PAUSE:
622 /* todo */
623 break;
625 case PCMREC_RESUME:
626 /* todo */
627 break;
629 case PCMREC_NEW_FILE:
630 /* todo */
631 break;
633 case PCMREC_SET_GAIN:
634 #if defined(HAVE_UDA1380)
635 uda1380_set_recvol(rec_gain, rec_gain, rec_volume);
636 #elif defined(HAVE_TLV320)
637 /* ToDo */
638 #endif
639 break;
641 case PCMREC_GOT_DATA:
642 pcmrec_callback(false);
643 break;
645 case SYS_USB_CONNECTED:
646 if (!is_recording && !is_stopping)
648 usb_acknowledge(SYS_USB_CONNECTED_ACK);
649 usb_wait_for_disconnect(&pcmrec_queue);
651 break;
655 logf("thread pcmrec done");
658 void pcmrec_set_mux(int source)
660 if(source == 0)
661 and_l(~0x00800000, &GPIO_OUT); /* Line In */
662 else
663 or_l(0x00800000, &GPIO_OUT); /* FM radio */
665 or_l(0x00800000, &GPIO_ENABLE);
666 or_l(0x00800000, &GPIO_FUNCTION);