summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2006-12-06 08:34:55 +0000
committerMichael Sevakis <jethead71@rockbox.org>2006-12-06 08:34:55 +0000
commit51189b4cb41fb70f4800286f99573f590941ddea (patch)
tree09ca4c9ee4f2ade25e811e5a1f9018a7814c78b3
parent1ff7652adf206eec517ae3236d02a5be9324942a (diff)
downloadrockbox-51189b4cb41fb70f4800286f99573f590941ddea.tar.gz
rockbox-51189b4cb41fb70f4800286f99573f590941ddea.zip
Small change to PCM recording API for low latency effects. Latency can be as low as 14 samples from input to output including the FIFOs (ColdFire) but 16 is more reasonable an expectation if only tranferring one sample per interrupt (\!). May convert PCM playback to use the same method as it can still be used in the old manner with some slight mods but has the potential to enable new features since it is more flexible.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11668 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h5
-rw-r--r--firmware/export/pcm_playback.h1
-rw-r--r--firmware/export/pcm_record.h17
-rw-r--r--firmware/pcm_record.c42
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c68
6 files changed, 61 insertions, 73 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 268fee5fd8..b129493471 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -482,6 +482,7 @@ static const struct plugin_api rockbox_api = {
482 482
483#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR) 483#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR)
484 sound_default, 484 sound_default,
485 pcm_record_more,
485#endif 486#endif
486}; 487};
487 488
diff --git a/apps/plugin.h b/apps/plugin.h
index 22f6b97fce..68841e8698 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -580,8 +580,8 @@ struct plugin_api {
580#ifndef SIMULATOR 580#ifndef SIMULATOR
581 void (*pcm_init_recording)(void); 581 void (*pcm_init_recording)(void);
582 void (*pcm_close_recording)(void); 582 void (*pcm_close_recording)(void);
583 void (*pcm_record_data)(pcm_more_callback_type more_ready, 583 void (*pcm_record_data)(pcm_more_callback_type2 more_ready,
584 unsigned char *start, size_t size); 584 void *start, size_t size);
585 void (*pcm_stop_recording)(void); 585 void (*pcm_stop_recording)(void);
586 void (*pcm_calculate_rec_peaks)(int *left, int *right); 586 void (*pcm_calculate_rec_peaks)(int *left, int *right);
587 void (*audio_set_recording_gain)(int left, int right, int type); 587 void (*audio_set_recording_gain)(int left, int right, int type);
@@ -598,6 +598,7 @@ struct plugin_api {
598 598
599#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR) 599#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(SIMULATOR)
600 int (*sound_default)(int setting); 600 int (*sound_default)(int setting);
601 void (*pcm_record_more)(void *start, size_t size);
601#endif 602#endif
602}; 603};
603 604
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index e7c00edeed..80a1f557fe 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -24,6 +24,7 @@
24/* Typedef for registered callback (play and record) */ 24/* Typedef for registered callback (play and record) */
25typedef void (*pcm_more_callback_type)(unsigned char **start, 25typedef void (*pcm_more_callback_type)(unsigned char **start,
26 size_t *size); 26 size_t *size);
27typedef int (*pcm_more_callback_type2)(int status);
27 28
28void pcm_init(void); 29void pcm_init(void);
29 30
diff --git a/firmware/export/pcm_record.h b/firmware/export/pcm_record.h
index 30d2dc7e6f..f6dddb3424 100644
--- a/firmware/export/pcm_record.h
+++ b/firmware/export/pcm_record.h
@@ -20,9 +20,9 @@
20#ifndef PCM_RECORD_H 20#ifndef PCM_RECORD_H
21#define PCM_RECORD_H 21#define PCM_RECORD_H
22 22
23#define DMA_REC_ERROR_DMA ((size_t)-1) 23#define DMA_REC_ERROR_DMA (-1)
24#ifdef HAVE_SPDIF_IN 24#ifdef HAVE_SPDIF_IN
25#define DMA_REC_ERROR_SPDIF ((size_t)-2) 25#define DMA_REC_ERROR_SPDIF (-2)
26#endif 26#endif
27 27
28/** 28/**
@@ -36,12 +36,15 @@ void pcm_init_recording(void);
36void pcm_close_recording(void); 36void pcm_close_recording(void);
37 37
38/* Start recording "raw" PCM data */ 38/* Start recording "raw" PCM data */
39void pcm_record_data(pcm_more_callback_type more_ready, 39void pcm_record_data(pcm_more_callback_type2 more_ready,
40 unsigned char *start, size_t size); 40 void *start, size_t size);
41 41
42/* Stop tranferring data into supplied buffer */ 42/* Stop tranferring data into supplied buffer */
43void pcm_stop_recording(void); 43void pcm_stop_recording(void);
44 44
45/* Continue transferring data in - call during interrupt handler */
46void pcm_record_more(void *start, size_t size);
47
45void pcm_calculate_rec_peaks(int *left, int *right); 48void pcm_calculate_rec_peaks(int *left, int *right);
46 49
47/** General functions for high level codec recording **/ 50/** General functions for high level codec recording **/
@@ -64,12 +67,12 @@ int pcm_get_num_unprocessed(void);
64/** The following are for internal use between pcm_record.c and target- 67/** The following are for internal use between pcm_record.c and target-
65 specific portion **/ 68 specific portion **/
66/* the registered callback function for when more data is available */ 69/* the registered callback function for when more data is available */
67extern volatile pcm_more_callback_type pcm_callback_more_ready; 70extern volatile pcm_more_callback_type2 pcm_callback_more_ready;
68/* DMA transfer in is currently active */ 71/* DMA transfer in is currently active */
69extern volatile bool pcm_recording; 72extern volatile bool pcm_recording;
70 73
71/* APIs implemented in the target-specific portion */ 74/* APIs implemented in the target-specific portion */
72extern void pcm_rec_dma_start(const void *addr, size_t size); 75extern void pcm_rec_dma_start(void *addr, size_t size);
73extern void pcm_rec_dma_stop(void); 76extern void pcm_rec_dma_stop(void);
74 77
75#endif /* PCM_RECORD_H */ 78#endif /* PCM_RECORD_H */
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 379adc3a9c..a72641baa6 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -55,13 +55,9 @@
55 be shared semi-privately **/ 55 be shared semi-privately **/
56 56
57/* the registered callback function for when more data is available */ 57/* the registered callback function for when more data is available */
58volatile pcm_more_callback_type pcm_callback_more_ready = NULL; 58volatile pcm_more_callback_type2 pcm_callback_more_ready = NULL;
59/* DMA transfer in is currently active */ 59/* DMA transfer in is currently active */
60volatile bool pcm_recording = false; 60volatile bool pcm_recording = false;
61
62/* APIs implemented in the target-specific portion */
63void pcm_rec_dma_start(const void *addr, size_t size);
64void pcm_rec_dma_stop(void);
65 61
66/** General recording state **/ 62/** General recording state **/
67static bool is_recording; /* We are recording */ 63static bool is_recording; /* We are recording */
@@ -225,16 +221,16 @@ static void pcm_thread_wait_for_stop(void)
225/*******************************************************************/ 221/*******************************************************************/
226 222
227/* Callback for when more data is ready */ 223/* Callback for when more data is ready */
228static void pcm_rec_have_more(unsigned char **data, size_t *size) 224static int pcm_rec_have_more(int status)
229{ 225{
230 if (*size != 0) 226 if (status < 0)
231 { 227 {
232 /* some error condition */ 228 /* some error condition */
233 if (*size == DMA_REC_ERROR_DMA) 229 if (status == DMA_REC_ERROR_DMA)
234 { 230 {
235 /* Flush recorded data to disk and stop recording */ 231 /* Flush recorded data to disk and stop recording */
236 queue_post(&pcmrec_queue, PCMREC_STOP, NULL); 232 queue_post(&pcmrec_queue, PCMREC_STOP, NULL);
237 return; 233 return -1;
238 } 234 }
239 /* else try again next transmission */ 235 /* else try again next transmission */
240 } 236 }
@@ -243,9 +239,9 @@ static void pcm_rec_have_more(unsigned char **data, size_t *size)
243 /* advance write position */ 239 /* advance write position */
244 dma_wr_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; 240 dma_wr_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK;
245 } 241 }
246 242
247 *data = (unsigned char *)GET_PCM_CHUNK(dma_wr_pos); 243 pcm_record_more(GET_PCM_CHUNK(dma_wr_pos), PCM_CHUNK_SIZE);
248 *size = PCM_CHUNK_SIZE; 244 return 0;
249} /* pcm_rec_have_more */ 245} /* pcm_rec_have_more */
250 246
251/** pcm_rec_* group **/ 247/** pcm_rec_* group **/
@@ -423,9 +419,9 @@ void audio_set_recording_options(struct audio_recording_options *options)
423 if (audio_load_encoder(enc_config.afmt)) 419 if (audio_load_encoder(enc_config.afmt))
424 { 420 {
425 /* start DMA transfer */ 421 /* start DMA transfer */
426 pcm_record_data(pcm_rec_have_more, NULL, 0);
427 /* do unlock after starting to prevent preincrement of dma_wr_pos */
428 dma_lock = pre_record_ticks == 0; 422 dma_lock = pre_record_ticks == 0;
423 pcm_record_data(pcm_rec_have_more, GET_PCM_CHUNK(dma_wr_pos),
424 PCM_CHUNK_SIZE);
429 } 425 }
430 else 426 else
431 { 427 {
@@ -1621,20 +1617,14 @@ size_t enc_unget_pcm_data(size_t size)
1621 * Functions that do not require targeted implementation but only a targeted 1617 * Functions that do not require targeted implementation but only a targeted
1622 * interface 1618 * interface
1623 */ 1619 */
1624void pcm_record_data(pcm_more_callback_type more_ready, 1620void pcm_record_data(pcm_more_callback_type2 more_ready,
1625 unsigned char *start, size_t size) 1621 void *start, size_t size)
1626{ 1622{
1627 pcm_callback_more_ready = more_ready;
1628
1629 if (!(start && size)) 1623 if (!(start && size))
1630 { 1624 return;
1631 size = 0;
1632 if (more_ready)
1633 more_ready(&start, &size);
1634 }
1635 1625
1636 if (start && size) 1626 pcm_callback_more_ready = more_ready;
1637 pcm_rec_dma_start(start, size); 1627 pcm_rec_dma_start(start, size);
1638} /* pcm_record_data */ 1628} /* pcm_record_data */
1639 1629
1640void pcm_stop_recording(void) 1630void pcm_stop_recording(void)
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 917800d0b8..4e4e557d9b 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -287,7 +287,7 @@ void DMA0(void)
287/**************************************************************************** 287/****************************************************************************
288 ** Recording DMA transfer 288 ** Recording DMA transfer
289 **/ 289 **/
290void pcm_rec_dma_start(const void *addr, size_t size) 290void pcm_rec_dma_start(void *addr, size_t size)
291{ 291{
292 logf("pcm_rec_dma_start"); 292 logf("pcm_rec_dma_start");
293 293
@@ -296,12 +296,6 @@ void pcm_rec_dma_start(const void *addr, size_t size)
296 296
297 pcm_recording = true; 297 pcm_recording = true;
298 298
299 DAR1 = (unsigned long)addr; /* Destination address */
300 SAR1 = (unsigned long)&PDIR2; /* Source address */
301 BCR1 = size; /* Bytes to transfer */
302
303 rec_peak_addr = (unsigned long *)addr;
304
305 pcm_apply_settings(false); 299 pcm_apply_settings(false);
306 300
307 /* Start the DMA transfer.. */ 301 /* Start the DMA transfer.. */
@@ -309,18 +303,22 @@ void pcm_rec_dma_start(const void *addr, size_t size)
309 INTERRUPTCLEAR = 0x03c00000; 303 INTERRUPTCLEAR = 0x03c00000;
310#endif 304#endif
311 305
312 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | 306 SAR1 = (unsigned long)&PDIR2; /* Source address */
313 DMA_DSIZE(3) | DMA_START; 307 DCR1 = DMA_INT | DMA_CS | DMA_AA | DMA_DINC | DMA_DSIZE(3);
308
309 pcm_record_more(addr, size);
310
311 DCR1 |= DMA_START;
314} /* pcm_dma_start */ 312} /* pcm_dma_start */
315 313
316void pcm_rec_dma_stop(void) 314void pcm_rec_dma_stop(void)
317{ 315{
318 logf("pcm_rec_dma_stop"); 316 logf("pcm_rec_dma_stop");
319 317
320 pcm_recording = false;
321
322 DCR1 = 0;
323 DSR1 = 1; /* Clear interrupt */ 318 DSR1 = 1; /* Clear interrupt */
319 DCR1 = 0;
320
321 pcm_recording = false;
324} /* pcm_dma_stop */ 322} /* pcm_dma_stop */
325 323
326void pcm_init_recording(void) 324void pcm_init_recording(void)
@@ -338,7 +336,7 @@ void pcm_init_recording(void)
338 336
339 pcm_rec_dma_stop(); 337 pcm_rec_dma_stop();
340 338
341 ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */ 339 ICR7 = (6 << 2); /* Enable interrupt at level 6, priority 0 */
342 IMR &= ~(1 << 15); /* bit 15 is DMA1 */ 340 IMR &= ~(1 << 15); /* bit 15 is DMA1 */
343} /* pcm_init_recording */ 341} /* pcm_init_recording */
344 342
@@ -359,17 +357,15 @@ void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
359void DMA1(void) 357void DMA1(void)
360{ 358{
361 int res = DSR1; 359 int res = DSR1;
362 pcm_more_callback_type more_ready; 360 int status = 0;
363 unsigned char *next_start; 361 pcm_more_callback_type2 more_ready;
364 ssize_t next_size = 0; /* passing <> 0 is indicates
365 an error condition */
366 362
367 DSR1 = 1; /* Clear interrupt */ 363 DSR1 = 1; /* Clear interrupt */
368 DCR1 &= ~DMA_EEXT; 364 DCR1 &= ~DMA_EEXT; /* Disable peripheral request */
369 365
370 if (res & 0x70) 366 if (res & 0x70)
371 { 367 {
372 next_size = DMA_REC_ERROR_DMA; 368 status = DMA_REC_ERROR_DMA;
373 logf("DMA1 err: 0x%x", res); 369 logf("DMA1 err: 0x%x", res);
374 } 370 }
375#ifdef HAVE_SPDIF_IN 371#ifdef HAVE_SPDIF_IN
@@ -377,37 +373,33 @@ void DMA1(void)
377 (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ 373 (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */
378 { 374 {
379 INTERRUPTCLEAR = 0x03c00000; 375 INTERRUPTCLEAR = 0x03c00000;
380 next_size = DMA_REC_ERROR_SPDIF; 376 status = DMA_REC_ERROR_SPDIF;
381 logf("spdif err"); 377 logf("spdif err");
382 } 378 }
383#endif 379#endif
384 380
385 more_ready = pcm_callback_more_ready; 381 more_ready = pcm_callback_more_ready;
386 382
387 if (more_ready) 383 if (more_ready != NULL && more_ready(status) >= 0)
388 more_ready(&next_start, &next_size);
389
390 if (next_size > 0)
391 {
392 /* Start peaking at dest */
393 rec_peak_addr = (unsigned long *)next_start;
394 DAR1 = (unsigned long)next_start; /* Destination address */
395 BCR1 = (unsigned long)next_size; /* Bytes to transfer */
396 DCR1 |= DMA_EEXT;
397 return; 384 return;
398 } 385
399 else
400 {
401#if 0 386#if 0
402 /* int. logfs can trash the display */ 387 /* int. logfs can trash the display */
403 logf("DMA1 No Data:0x%04x", res); 388 logf("DMA1 done:%04x %d", res, status);
404#endif 389#endif
405 }
406
407 /* Finished recording */ 390 /* Finished recording */
408 pcm_rec_dma_stop(); 391 pcm_rec_dma_stop();
409} /* DMA1 */ 392} /* DMA1 */
410 393
394/* Continue transferring data in */
395void pcm_record_more(void *start, size_t size)
396{
397 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
398 DAR1 = (unsigned long)start; /* Destination address */
399 BCR1 = (unsigned long)size; /* Bytes to transfer */
400 DCR1 |= DMA_EEXT;
401}
402
411void pcm_mute(bool mute) 403void pcm_mute(bool mute)
412{ 404{
413 ac_mute(mute); 405 ac_mute(mute);