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.c717
1 files changed, 469 insertions, 248 deletions
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 8b46a09ed3..b167d6a562 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -30,11 +30,7 @@
30 30
31#include "cpu.h" 31#include "cpu.h"
32#include "i2c.h" 32#include "i2c.h"
33#if defined(HAVE_UDA1380)
34#include "uda1380.h" 33#include "uda1380.h"
35#elif defined(HAVE_TLV320)
36#include "tlv320.h"
37#endif
38#include "system.h" 34#include "system.h"
39#include "usb.h" 35#include "usb.h"
40 36
@@ -56,47 +52,56 @@
56static volatile bool is_recording; /* We are recording */ 52static volatile bool is_recording; /* We are recording */
57static volatile bool is_stopping; /* Are we going to stop */ 53static volatile bool is_stopping; /* Are we going to stop */
58static volatile bool is_paused; /* We have paused */ 54static volatile bool is_paused; /* We have paused */
55static volatile bool is_error; /* An error has occured */
59 56
60static volatile int num_rec_bytes; 57static volatile unsigned long num_rec_bytes; /* Num bytes recorded */
58static volatile unsigned long num_file_bytes; /* Num bytes written to current file */
61static volatile int int_count; /* Number of DMA completed interrupts */ 59static volatile int int_count; /* Number of DMA completed interrupts */
62static volatile int error_count; /* Number of DMA errors */ 60static volatile int error_count; /* Number of DMA errors */
63 61
64static unsigned long record_start_time; /* Value of current_tick when recording was started */ 62static unsigned long record_start_time; /* Value of current_tick when recording was started */
65static unsigned long pause_start_time; /* Value of current_tick when pause was started */ 63static unsigned long pause_start_time; /* Value of current_tick when pause was started */
66 64
67static int rec_gain, rec_volume;
68static bool show_waveform; 65static bool show_waveform;
69static int init_done = 0; 66
70static int wav_file; 67static int wav_file;
71static char recording_filename[MAX_PATH]; 68static char recording_filename[MAX_PATH];
72 69
70static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done;
71
73/***************************************************************************/ 72/***************************************************************************/
74 73
75/* 74/*
76 Some estimates: 75 Some estimates:
77 44100 HZ * 4 = 176400 bytes/s 76 Normal recording rate: 44100 HZ * 4 = 176 KB/s
78 Refresh LCD 10 HZ = 176400 / 10 = 17640 bytes ~=~ 1024*16 bytes 77 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..
79 84
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
82*/ 85*/
83 86
84#define NUM_BUFFERS 80 87#define CHUNK_SIZE 65536 /* Multiple of 4 */
85#define EACH_BUFFER_SIZE (1024*16) /* Multiple of 4. Use small value to get responsive waveform */ 88#define WRITE_THRESHOLD 30 /* Write when this many chunks (or less) until buffer full */
86#define ALL_BUFFERS_SIZE (NUM_BUFFERS * EACH_BUFFER_SIZE) 89
90#define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)])
87 91
88#define WRITE_THRESHOLD 40 /* Minimum number of buffers before write to file */ 92static unsigned char *rec_buffer; /* Circular recording buffer */
93static int num_chunks; /* Number of chunks available in rec_buffer */
89 94
90static unsigned char *rec_buffers[NUM_BUFFERS];
91 95
92/* 96/*
93 Overrun occures when DMA needs to write a new buffer and write_index == read_index 97 Overrun occures when DMA needs to write a new chunk and write_index == read_index
94 Solution to this is to optimize pcmrec_callback, use cpu_boost somewhere or increase 98 Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk
95 the total buffer size (or WRITE_THRESHOLD) 99 more often.
96*/ 100*/
97 101
98static int write_index; /* Which buffer the DMA is currently recording */ 102static volatile int write_index; /* Current chunk the DMA is writing to */
99static int read_index; /* The oldest buffer that the pcmrec_callback has not read */ 103static volatile int read_index; /* Oldest chunk that is not written to disk */
104static volatile int read2_index; /* Latest chunk that has not been converted to little endian */
100 105
101/***************************************************************************/ 106/***************************************************************************/
102 107
@@ -105,10 +110,13 @@ static long pcmrec_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(lon
105static const char pcmrec_thread_name[] = "pcmrec"; 110static const char pcmrec_thread_name[] = "pcmrec";
106 111
107static void pcmrec_thread(void); 112static void pcmrec_thread(void);
113static void pcmrec_dma_start(void);
114static void pcmrec_dma_stop(void);
108 115
109/* Event IDs */ 116/* Event IDs */
110#define PCMREC_OPEN 1 /* Enable recording */ 117#define PCMREC_INIT 1 /* Enable recording */
111#define PCMREC_CLOSE 2 /* Disable recording */ 118#define PCMREC_CLOSE 2
119
112#define PCMREC_START 3 /* Start a new recording */ 120#define PCMREC_START 3 /* Start a new recording */
113#define PCMREC_STOP 4 /* Stop the current recording */ 121#define PCMREC_STOP 4 /* Stop the current recording */
114#define PCMREC_PAUSE 10 122#define PCMREC_PAUSE 10
@@ -122,71 +130,58 @@ static void pcmrec_thread(void);
122/* Functions that are not executing in the pcmrec_thread first */ 130/* Functions that are not executing in the pcmrec_thread first */
123/*******************************************************************/ 131/*******************************************************************/
124 132
125void pcm_init_recording(void) 133/* Creates pcmrec_thread */
134void pcm_rec_init(void)
126{ 135{
127 int_count = 0;
128 error_count = 0;
129
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;
137
138 queue_init(&pcmrec_queue); 136 queue_init(&pcmrec_queue);
139 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name); 137 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name);
140} 138}
141 139
142void pcm_open_recording(void)
143{
144 init_done = 0;
145
146 logf("pcm_open_rec");
147
148 queue_post(&pcmrec_queue, PCMREC_OPEN, 0);
149 140
150 while (init_done) 141/* Initializes recording:
151 { 142 * - Set up the UDA1380 for recording
152 sleep(HZ >> 8); 143 * - Prepare for DMA transfers
153 } 144 */
154 145
155 logf("pcm_open_rec done"); 146void audio_init_recording(void)
147{
148 init_done = false;
149 queue_post(&pcmrec_queue, PCMREC_INIT, 0);
150
151 while(!init_done)
152 sleep_thread();
153 wake_up_thread();
156} 154}
157 155
158void pcm_close_recording(void) 156void audio_close_recording(void)
159{ 157{
160 /* todo: synchronize completion with pcmrec thread */ 158 close_done = false;
161 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); 159 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
160
161 while(!close_done)
162 sleep_thread();
163 wake_up_thread();
162} 164}
163 165
164 166unsigned long pcm_rec_status(void)
165
166unsigned long pcm_status(void)
167{ 167{
168 unsigned long ret = 0; 168 unsigned long ret = 0;
169 169
170 if (is_recording) 170 if (is_recording)
171 ret |= AUDIO_STATUS_RECORD; 171 ret |= AUDIO_STATUS_RECORD;
172 if (is_paused)
173 ret |= AUDIO_STATUS_PAUSE;
174 if (is_error)
175 ret |= AUDIO_STATUS_ERROR;
172 176
173 return ret; 177 return ret;
174} 178}
175 179
176 180unsigned long audio_recorded_time(void)
177
178void pcm_new_file(const char *filename)
179{
180 /* todo */
181 filename = filename;
182
183}
184
185unsigned long pcm_recorded_time(void)
186{ 181{
187 if (is_recording) 182 if (is_recording)
188 { 183 {
189 if(is_paused) 184 if (is_paused)
190 return pause_start_time - record_start_time; 185 return pause_start_time - record_start_time;
191 else 186 else
192 return current_tick - record_start_time; 187 return current_tick - record_start_time;
@@ -195,92 +190,168 @@ unsigned long pcm_recorded_time(void)
195 return 0; 190 return 0;
196} 191}
197 192
198unsigned long pcm_num_recorded_bytes(void) 193unsigned long audio_num_recorded_bytes(void)
199{ 194{
200
201 if (is_recording) 195 if (is_recording)
202 {
203 return num_rec_bytes; 196 return num_rec_bytes;
204 }
205 else
206 return 0;
207}
208
209void pcm_pause_recording(void)
210{
211 /* todo */
212}
213 197
214void pcm_resume_recording(void) 198 return 0;
215{
216 /* todo */
217} 199}
218 200
219 201
220/** 202/**
221 * Sets the audio source 203 * Sets the audio source
222 * 204 *
223 * Side effect: This functions starts feeding the CPU with audio data over the I2S bus 205 * This functions starts feeding the CPU with audio data over the I2S bus
224 * 206 *
225 * @param source 0=line-in, 1=mic 207 * @param source 0=mic, 1=line-in, (todo: 2=spdif)
226 */ 208 */
227void pcm_set_recording_options(int source, bool enable_waveform) 209void audio_set_recording_options(int frequency, int quality,
210 int source, int channel_mode,
211 bool editable, int prerecord_time,
212 bool monitor)
228{ 213{
229#if defined(HAVE_UDA1380) 214 /* TODO: */
230 uda1380_enable_recording(source); 215 (void)frequency;
231#elif defined(HAVE_TLV320) 216 (void)quality;
232 tlv320_enable_recording(source); 217 (void)channel_mode;
233#endif 218 (void)editable;
234 show_waveform = enable_waveform; 219 (void)prerecord_time;
220
221 //logf("pcmrec: src=%d", source);
222
223 switch (source)
224 {
225 /* mic */
226 case 0:
227 uda1380_enable_recording(true);
228 break;
229
230 /* line-in */
231 case 1:
232 uda1380_enable_recording(false);
233 break;
234 }
235
236 uda1380_set_monitor(monitor);
235} 237}
236 238
237 239
238/** 240/**
241 * Note that microphone is mono, only left value is used
242 * See uda1380_set_recvol() for exact ranges.
239 * 243 *
240 * @param gain line-in and microphone gain (0-15) 244 * @param type 0=line-in (radio), 1=mic, 2=ADC
241 * @param volume ADC volume (0-255) 245 *
242 */ 246 */
243void pcm_set_recording_gain(int gain, int volume) 247void audio_set_recording_gain(int left, int right, int type)
244{ 248{
245 rec_gain = gain; 249 //logf("rcmrec: t=%d l=%d r=%d", type, left, right);
246 rec_volume = volume; 250 uda1380_set_recvol(left, right, type);
247
248 queue_post(&pcmrec_queue, PCMREC_SET_GAIN, 0);
249} 251}
250 252
253
251/** 254/**
252 * Start recording 255 * Start recording
253 * 256 *
254 * Use pcm_set_recording_options before calling record 257 * Use audio_set_recording_options first to select recording options
255 */ 258 */
256void pcm_record(const char *filename) 259void audio_record(const char *filename)
257{ 260{
261 if (is_recording)
262 {
263 logf("record while recording");
264 return;
265 }
266
258 strncpy(recording_filename, filename, MAX_PATH - 1); 267 strncpy(recording_filename, filename, MAX_PATH - 1);
259 recording_filename[MAX_PATH - 1] = 0; 268 recording_filename[MAX_PATH - 1] = 0;
260 269
270 record_done = false;
261 queue_post(&pcmrec_queue, PCMREC_START, 0); 271 queue_post(&pcmrec_queue, PCMREC_START, 0);
272
273 while(!record_done)
274 sleep_thread();
275 wake_up_thread();
276}
277
278
279void audio_new_file(const char *filename)
280{
281 logf("pcm_new_file");
282
283 new_file_done = false;
284
285 strncpy(recording_filename, filename, MAX_PATH - 1);
286 recording_filename[MAX_PATH - 1] = 0;
287
288 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
289
290 while(!new_file_done)
291 sleep_thread();
292 wake_up_thread();
293
294 logf("pcm_new_file done");
262} 295}
263 296
264/** 297/**
265 * 298 *
266 */ 299 */
267void pcm_stop_recording(void) 300void audio_stop_recording(void)
268{ 301{
269 if (is_recording) 302 if (!is_recording)
270 is_stopping = 1; 303 return;
271 304
305 logf("pcm_stop");
306
307 stop_done = false;
272 queue_post(&pcmrec_queue, PCMREC_STOP, 0); 308 queue_post(&pcmrec_queue, PCMREC_STOP, 0);
273 309
274 logf("pcm_stop_recording"); 310 while(!stop_done)
311 sleep_thread();
312 wake_up_thread();
313
314 logf("pcm_stop done");
315}
275 316
276 while (is_stopping) 317void audio_pause_recording(void)
318{
319 if (!is_recording)
320 {
321 logf("pause when not recording");
322 return;
323 }
324 if (is_paused)
277 { 325 {
278 sleep(HZ >> 4); 326 logf("pause when paused");
327 return;
279 } 328 }
329
330 pause_done = false;
331 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
280 332
281 logf("pcm_stop_recording done"); 333 while(!pause_done)
334 sleep_thread();
335 wake_up_thread();
282} 336}
283 337
338void audio_resume_recording(void)
339{
340 if (!is_paused)
341 {
342 logf("resume when not paused");
343 return;
344 }
345
346 resume_done = false;
347 queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
348
349 while(!resume_done)
350 sleep_thread();
351 wake_up_thread();
352}
353
354
284 355
285/***************************************************************************/ 356/***************************************************************************/
286/* Functions that executes in the context of pcmrec_thread */ 357/* Functions that executes in the context of pcmrec_thread */
@@ -288,100 +359,116 @@ void pcm_stop_recording(void)
288 359
289 360
290/** 361/**
291 * Process the buffers using read_index and write_index. 362 * Process the chunks using read_index and write_index.
292 * 363 *
293 * DMA1 handler posts to pcmrec_queue so that pcmrec_thread calls this 364 * DMA1 handler posts to pcmrec_queue and pcmrec_thread calls this
294 * function. Also pcmrec_stop will call this function when the recording 365 * function.
295 * is stopping, and that call will have flush = true. 366 *
367 * Other function can also call this function with flush = true when
368 * they want to save everything recorded sofar to disk.
296 * 369 *
297 */ 370 */
298 371
299void pcmrec_callback(bool flush) __attribute__ ((section (".icode"))); 372static void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
300void pcmrec_callback(bool flush) 373static void pcmrec_callback(bool flush)
301{ 374{
302 int num_ready; 375 int num_ready, num_free, num_new;
376 unsigned short *ptr;
377 int i, j, w;
378
379 w = write_index;
380
381 num_new = w - read2_index;
382 if (num_new < 0)
383 num_new += num_chunks;
384
385 for (i=0; i<num_new; i++)
386 {
387 /* Convert the samples to little-endian so we only have to write later
388 (Less hd-spinning time)
389 */
390 ptr = GET_CHUNK(read2_index);
391 for (j=0; j<CHUNK_SIZE/2; j++)
392 {
393 /* TODO: might be a good place to add the peak-meter.. */
394
395 *ptr = htole16(*ptr);
396 ptr++;
397 }
398
399 num_rec_bytes += CHUNK_SIZE;
400
401 read2_index++;
402 if (read2_index >= num_chunks)
403 read2_index = 0;
404 }
303 405
304 num_ready = write_index - read_index; 406 num_ready = w - read_index;
305 if (num_ready < 0) 407 if (num_ready < 0)
306 num_ready += NUM_BUFFERS; 408 num_ready += num_chunks;
307
308 /* we can consume up to num_ready buffers */
309 409
310#ifdef HAVE_REMOTE_LCD 410 if (num_ready >= num_chunks)
311 /* Draw waveform on remote LCD */
312 if (show_waveform && num_ready>0)
313 { 411 {
314 short *buf; 412 logf("num_ready overflow?");
315 long x,y,offset; 413 num_ready = num_chunks-1;
316 int show_index; 414 }
317
318 /* Just display the last buffer (most recent one) */
319 show_index = read_index + num_ready - 1;
320 buf = (short*)rec_buffers[show_index];
321
322 lcd_remote_clear_display();
323
324 offset = 0;
325 for (x=0; x<LCD_REMOTE_WIDTH-1; x++)
326 {
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;
330 415
331 if (y < 2) y=2; 416 num_free = num_chunks - num_ready;
332 if (y >= LCD_REMOTE_HEIGHT-2) y = LCD_REMOTE_HEIGHT-2;
333 417
334 lcd_remote_drawpixel(x,y); 418 if (wav_file == -1 || (!is_recording && !flush))
419 {
420 /* In this case we should consume the buffers to avoid */
421 /* getting 'dma1 overrun' */
335 422
336 offset += (EACH_BUFFER_SIZE/2) / LCD_REMOTE_WIDTH; 423 read_index+=num_ready;
337 } 424 if (read_index >= num_chunks)
425 read_index -= num_chunks;
338 426
339 lcd_remote_update(); 427 return;
340 } 428 }
341 429
342#endif 430 if (num_free <= WRITE_THRESHOLD || flush)
343
344 /* Note: This might be a good place to call the 'codec' later */
345
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)
349 { 431 {
350 if (num_ready >= WRITE_THRESHOLD || flush) 432 logf("writing: %d (%d)", num_ready, flush);
433
434 for (i=0; i<num_ready; i++)
351 { 435 {
352 unsigned short *ptr = (unsigned short*)rec_buffers[read_index]; 436 if (write(wav_file, GET_CHUNK(read_index), CHUNK_SIZE) != CHUNK_SIZE)
353 int i;
354
355 for (i=0; i<EACH_BUFFER_SIZE * num_ready / 2; i++)
356 { 437 {
357 *ptr = htole16(*ptr); 438 logf("pcmrec: write err");
358 ptr++; 439 pcmrec_dma_stop();
440 return;
359 } 441 }
360 442
361 write(wav_file, rec_buffers[read_index], EACH_BUFFER_SIZE * num_ready); 443 num_file_bytes += CHUNK_SIZE;
362 444
363 read_index+=num_ready; 445 read_index++;
364 if (read_index >= NUM_BUFFERS) 446 if (read_index >= num_chunks)
365 read_index -= NUM_BUFFERS; 447 read_index = 0;
366 } 448 }
367 449
368 } else 450 logf("done");
369 {
370 /* In this case we must consume the buffers otherwise we will */
371 /* get 'dma1 overrun' pretty fast */
372
373 read_index+=num_ready;
374 if (read_index >= NUM_BUFFERS)
375 read_index -= NUM_BUFFERS;
376 } 451 }
377} 452}
378 453
454/* Abort dma transfer */
455static void pcmrec_dma_stop(void)
456{
457 DCR1 = 0;
458
459 is_error = true;
460 is_recording = false;
461
462 error_count++;
463
464 logf("dma1 stopped");
465}
379 466
380void pcmrec_dma_start(void) 467static void pcmrec_dma_start(void)
381{ 468{
382 DAR1 = (unsigned long)rec_buffers[write_index++]; /* Destination address */ 469 DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
383 SAR1 = (unsigned long)&PDIR2; /* Source address */ 470 SAR1 = (unsigned long)&PDIR2; /* Source address */
384 BCR1 = EACH_BUFFER_SIZE; /* Bytes to transfer */ 471 BCR1 = CHUNK_SIZE; /* Bytes to transfer */
385 472
386 /* Start the DMA transfer.. */ 473 /* Start the DMA transfer.. */
387 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; 474 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START;
@@ -404,36 +491,37 @@ void DMA1(void)
404 { 491 {
405 DCR1 = 0; /* Stop DMA transfer */ 492 DCR1 = 0; /* Stop DMA transfer */
406 error_count++; 493 error_count++;
407 is_recording = 0; 494 is_recording = false;
408 495
409 logf("dma1 err 0x%x", res); 496 logf("dma1 err 0x%x", res);
497
498 /* Flush recorded data to disk and stop recording */
499 queue_post(&pcmrec_queue, PCMREC_STOP, NULL);
410 500
411 } else 501 } else
412 { 502 {
413 num_rec_bytes += EACH_BUFFER_SIZE;
414
415 write_index++; 503 write_index++;
416 if (write_index >= NUM_BUFFERS) 504 if (write_index >= num_chunks)
417 write_index = 0; 505 write_index = 0;
418 506
419 if (is_stopping || !is_recording) 507 if (is_stopping || !is_recording)
420 { 508 {
421 DCR1 = 0; /* Stop DMA transfer */ 509 DCR1 = 0; /* Stop DMA transfer */
422 is_recording = 0; 510 is_stopping = false;
423 511
424 logf("dma1 stopping"); 512 logf("dma1 stopping");
425 513
426 } else if (write_index == read_index) 514 } else if (write_index == read_index)
427 { 515 {
428 DCR1 = 0; /* Stop DMA transfer */ 516 DCR1 = 0; /* Stop DMA transfer */
429 is_recording = 0; 517 is_recording = false;
430 518
431 logf("dma1 overrun"); 519 logf("dma1 overrun");
432 520
433 } else 521 } else
434 { 522 {
435 DAR1 = (unsigned long)rec_buffers[write_index]; /* Destination address */ 523 DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
436 BCR1 = EACH_BUFFER_SIZE; 524 BCR1 = CHUNK_SIZE;
437 525
438 queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL); 526 queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL);
439 527
@@ -443,6 +531,8 @@ void DMA1(void)
443 IPR |= (1<<15); /* Clear pending interrupt request */ 531 IPR |= (1<<15); /* Clear pending interrupt request */
444} 532}
445 533
534/* Create WAVE file and write header */
535/* Sets returns 0 if success, -1 on failure */
446static int start_wave(void) 536static int start_wave(void)
447{ 537{
448 unsigned char header[44] = 538 unsigned char header[44] =
@@ -456,7 +546,8 @@ static int start_wave(void)
456 if (wav_file < 0) 546 if (wav_file < 0)
457 { 547 {
458 wav_file = -1; 548 wav_file = -1;
459 logf("create failed: %d", wav_file); 549 logf("rec: create failed: %d", wav_file);
550 is_error = true;
460 return -1; 551 return -1;
461 } 552 }
462 553
@@ -464,8 +555,9 @@ static int start_wave(void)
464 { 555 {
465 close(wav_file); 556 close(wav_file);
466 wav_file = -1; 557 wav_file = -1;
467 logf("write failed"); 558 logf("rec: write failed");
468 return -2; 559 is_error = true;
560 return -1;
469 } 561 }
470 562
471 return 0; 563 return 0;
@@ -476,16 +568,19 @@ static void close_wave(void)
476{ 568{
477 long l; 569 long l;
478 570
479 l = htole32(num_rec_bytes + 36); 571 if (wav_file != -1)
480 lseek(wav_file, 4, SEEK_SET); 572 {
481 write(wav_file, &l, 4); 573 l = htole32(num_file_bytes + 36);
482 574 lseek(wav_file, 4, SEEK_SET);
483 l = htole32(num_rec_bytes); 575 write(wav_file, &l, 4);
484 lseek(wav_file, 40, SEEK_SET); 576
485 write(wav_file, &l, 4); 577 l = htole32(num_file_bytes);
486 578 lseek(wav_file, 40, SEEK_SET);
487 close(wav_file); 579 write(wav_file, &l, 4);
488 wav_file = -1; 580
581 close(wav_file);
582 wav_file = -1;
583 }
489} 584}
490 585
491static void pcmrec_start(void) 586static void pcmrec_start(void)
@@ -493,74 +588,206 @@ static void pcmrec_start(void)
493 logf("pcmrec_start"); 588 logf("pcmrec_start");
494 589
495 if (is_recording) 590 if (is_recording)
591 {
592 logf("already recording");
593 record_done = true;
496 return; 594 return;
497 595 }
596
498 if (wav_file != -1) 597 if (wav_file != -1)
499 close(wav_file); 598 close(wav_file);
500 599
501 logf("rec: %s", recording_filename); 600 if (start_wave() != 0)
502 601 {
503 start_wave(); /* todo: send signal to pcm_record if we have failed */ 602 /* failed to create the file */
504 603 record_done = true;
604 return;
605 }
606
505 num_rec_bytes = 0; 607 num_rec_bytes = 0;
506 608 num_file_bytes = 0;
507 /* Store the current time */
508 record_start_time = current_tick; 609 record_start_time = current_tick;
509 610 pause_start_time = 0;
611
510 write_index = 0; 612 write_index = 0;
511 read_index = 0; 613 read_index = 0;
614 read2_index = 0;
512 615
513 is_stopping = 0; 616 is_stopping = false;
514 is_paused = 0; 617 is_paused = false;
515 is_recording = 1; 618 is_recording = true;
516 619
517 pcmrec_dma_start(); 620 pcmrec_dma_start();
518 621
622 record_done = true;
519} 623}
520 624
521static void pcmrec_stop(void) 625static void pcmrec_stop(void)
522{ 626{
523 /* wait for recording to finish */ 627 logf("pcmrec_stop");
628
629 if (!is_recording)
630 {
631 stop_done = true;
632 return;
633 }
634
635 if (!is_paused)
636 {
637 /* wait for recording to finish */
638 is_stopping = true;
639
640 while (is_stopping && is_recording)
641 sleep_thread();
642 wake_up_thread();
643
644 is_stopping = false;
645 }
646
647 is_recording = false;
648
649 /* Flush buffers to file */
650 pcmrec_callback(true);
524 651
525 /* todo: Abort current DMA transfer using DCR1.. */ 652 close_wave();
526 653
527 logf("pcmrec_stop"); 654 stop_done = true;
655
656 logf("pcmrec_stop done");
657}
528 658
529 while (is_recording) 659static void pcmrec_new_file(void)
660{
661 logf("pcmrec_new_file");
662
663 if (!is_recording)
530 { 664 {
531 sleep(HZ >> 4); 665 logf("not recording");
666 new_file_done = true;
667 return;
532 } 668 }
669
670 /* Since pcmrec_callback() blocks until the data has been written,
671 here is a good approximation when recording to the new file starts
672 */
673 record_start_time = current_tick;
674 num_rec_bytes = 0;
675
676 if (is_paused)
677 pause_start_time = record_start_time;
678
679 /* Flush what we got in buffers to file */
680 pcmrec_callback(true);
681
682 close_wave();
533 683
534 logf("pcmrec_stop done"); 684 num_file_bytes = 0;
685
686 /* start the new file */
687 if (start_wave() != 0)
688 {
689 logf("new_file failed");
690 pcmrec_stop();
691 }
535 692
536 /* Write unfinished buffers to file */ 693 new_file_done = true;
694 logf("pcmrec_new_file done");
695}
696
697static void pcmrec_pause(void)
698{
699 logf("pcmrec_pause");
700
701 if (!is_recording)
702 {
703 logf("pause: not recording");
704 pause_done = true;
705 return;
706 }
707
708 /* Abort DMA transfer and flush to file? */
709
710 is_stopping = true;
711
712 while (is_stopping && is_recording)
713 sleep_thread();
714 wake_up_thread();
715
716 pause_start_time = current_tick;
717 is_paused = true;
718
719 /* Flush what we got in buffers to file */
537 pcmrec_callback(true); 720 pcmrec_callback(true);
721
722 pause_done = true;
723
724 logf("pcmrec_pause done");
725}
538 726
539 close_wave();
540 727
541 is_stopping = 0; 728static void pcmrec_resume(void)
729{
730 logf("pcmrec_resume");
731
732 if (!is_paused)
733 {
734 logf("resume: not paused");
735 resume_done = true;
736 return;
737 }
738
739 is_paused = false;
740 is_recording = true;
741
742 /* Compensate for the time we have been paused */
743 if (pause_start_time)
744 {
745 record_start_time += current_tick - pause_start_time;
746 pause_start_time = 0;
747 }
748
749 pcmrec_dma_start();
750
751 resume_done = true;
752
753 logf("pcmrec_resume done");
542} 754}
543 755
544static void pcmrec_open(void) 756
757/**
758 * audio_init_recording calls this function using PCMREC_INIT
759 *
760 */
761static void pcmrec_init(void)
545{ 762{
546 unsigned long buffer_start; 763 unsigned long buffer_size;
547 int i;
548 764
549 show_waveform = 0; 765 show_waveform = 0;
550 is_recording = 0;
551 is_stopping = 0;
552 num_rec_bytes = 0;
553 wav_file = -1; 766 wav_file = -1;
554 read_index = 0; 767 read_index = 0;
768 read2_index = 0;
555 write_index = 0; 769 write_index = 0;
556 770
557 buffer_start = (unsigned long)(&audiobuf[(audiobufend - audiobuf) - (ALL_BUFFERS_SIZE + 16)]); 771 num_rec_bytes = 0;
558 buffer_start &= ~3; 772 num_file_bytes = 0;
559 773 record_start_time = 0;
560 for (i=0; i<NUM_BUFFERS; i++) 774 pause_start_time = 0;
561 { 775
562 rec_buffers[i] = (unsigned char*)(buffer_start + EACH_BUFFER_SIZE * i); 776 is_recording = false;
563 } 777 is_stopping = false;
778 is_paused = false;
779 is_error = false;
780
781 rec_buffer = (unsigned char*)(((unsigned long)audiobuf) & ~3);
782 buffer_size = (long)audiobufend - (long)audiobuf - 16;
783
784 //buffer_size = 1024*1024*5;
785
786 logf("buf size: %d kb", buffer_size/1024);
787
788 num_chunks = buffer_size / CHUNK_SIZE;
789
790 logf("num_chunks: %d", num_chunks);
564 791
565 IIS1CONFIG = 0x800; /* Stop any playback */ 792 IIS1CONFIG = 0x800; /* Stop any playback */
566 AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ 793 AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
@@ -578,16 +805,13 @@ static void pcmrec_open(void)
578 805
579static void pcmrec_close(void) 806static void pcmrec_close(void)
580{ 807{
581#if defined(HAVE_UDA1380)
582 uda1380_disable_recording(); 808 uda1380_disable_recording();
583#elif defined(HAVE_TLV320)
584 tlv320_disable_recording();
585#endif
586 809
587 DMAROUTE = (DMAROUTE & 0xffff00ff); 810 DMAROUTE = (DMAROUTE & 0xffff00ff);
588 ICR7 = 0x00; /* Disable interrupt */ 811 ICR7 = 0x00; /* Disable interrupt */
589 IMR |= (1<<15); /* bit 15 is DMA1 */ 812 IMR |= (1<<15); /* bit 15 is DMA1 */
590 813
814 close_done = true;
591} 815}
592 816
593static void pcmrec_thread(void) 817static void pcmrec_thread(void)
@@ -596,14 +820,17 @@ static void pcmrec_thread(void)
596 820
597 logf("thread pcmrec start"); 821 logf("thread pcmrec start");
598 822
823 int_count = 0;
824 error_count = 0;
825
599 while (1) 826 while (1)
600 { 827 {
601 queue_wait(&pcmrec_queue, &ev); 828 queue_wait(&pcmrec_queue, &ev);
602 829
603 switch (ev.id) 830 switch (ev.id)
604 { 831 {
605 case PCMREC_OPEN: 832 case PCMREC_INIT:
606 pcmrec_open(); 833 pcmrec_init();
607 break; 834 break;
608 835
609 case PCMREC_CLOSE: 836 case PCMREC_CLOSE:
@@ -619,25 +846,18 @@ static void pcmrec_thread(void)
619 break; 846 break;
620 847
621 case PCMREC_PAUSE: 848 case PCMREC_PAUSE:
622 /* todo */ 849 pcmrec_pause();
623 break; 850 break;
624 851
625 case PCMREC_RESUME: 852 case PCMREC_RESUME:
626 /* todo */ 853 pcmrec_resume();
627 break; 854 break;
628 855
629 case PCMREC_NEW_FILE: 856 case PCMREC_NEW_FILE:
630 /* todo */ 857 pcmrec_new_file();
631 break;
632
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; 858 break;
640 859
860 /* Notification by DMA interrupt */
641 case PCMREC_GOT_DATA: 861 case PCMREC_GOT_DATA:
642 pcmrec_callback(false); 862 pcmrec_callback(false);
643 break; 863 break;
@@ -655,7 +875,8 @@ static void pcmrec_thread(void)
655 logf("thread pcmrec done"); 875 logf("thread pcmrec done");
656} 876}
657 877
658void pcmrec_set_mux(int source) 878/* Select VINL & VINR source: 0=Line-in, 1=FM Radio */
879void pcm_rec_mux(int source)
659{ 880{
660 if(source == 0) 881 if(source == 0)
661 and_l(~0x00800000, &GPIO_OUT); /* Line In */ 882 and_l(~0x00800000, &GPIO_OUT); /* Line In */