diff options
Diffstat (limited to 'firmware/pcm.c')
-rw-r--r-- | firmware/pcm.c | 150 |
1 files changed, 92 insertions, 58 deletions
diff --git a/firmware/pcm.c b/firmware/pcm.c index a69f0a8232..8080823077 100644 --- a/firmware/pcm.c +++ b/firmware/pcm.c | |||
@@ -39,6 +39,7 @@ | |||
39 | * pcm_play_lock | 39 | * pcm_play_lock |
40 | * pcm_play_unlock | 40 | * pcm_play_unlock |
41 | * Semi-private - | 41 | * Semi-private - |
42 | * pcm_play_get_more_callback | ||
42 | * pcm_play_dma_init | 43 | * pcm_play_dma_init |
43 | * pcm_play_dma_start | 44 | * pcm_play_dma_start |
44 | * pcm_play_dma_stop | 45 | * pcm_play_dma_stop |
@@ -48,28 +49,27 @@ | |||
48 | * pcm_sampr (R) | 49 | * pcm_sampr (R) |
49 | * pcm_fsel (R) | 50 | * pcm_fsel (R) |
50 | * pcm_curr_sampr (R) | 51 | * pcm_curr_sampr (R) |
51 | * pcm_callback_for_more (R) | ||
52 | * pcm_playing (R) | 52 | * pcm_playing (R) |
53 | * pcm_paused (R) | 53 | * pcm_paused (R) |
54 | * | 54 | * |
55 | * ==Playback/Recording== | 55 | * ==Playback/Recording== |
56 | * Public - | ||
57 | * pcm_dma_addr | ||
56 | * Semi-private - | 58 | * Semi-private - |
57 | * pcm_dma_apply_settings | 59 | * pcm_dma_apply_settings |
58 | * pcm_dma_addr | ||
59 | * | 60 | * |
60 | * ==Recording== | 61 | * ==Recording== |
61 | * Public - | 62 | * Public - |
62 | * pcm_rec_lock | 63 | * pcm_rec_lock |
63 | * pcm_rec_unlock | 64 | * pcm_rec_unlock |
64 | * Semi-private - | 65 | * Semi-private - |
66 | * pcm_rec_more_ready_callback | ||
65 | * pcm_rec_dma_init | 67 | * pcm_rec_dma_init |
66 | * pcm_rec_dma_close | 68 | * pcm_rec_dma_close |
67 | * pcm_rec_dma_start | 69 | * pcm_rec_dma_start |
68 | * pcm_rec_dma_record_more | ||
69 | * pcm_rec_dma_stop | 70 | * pcm_rec_dma_stop |
70 | * pcm_rec_dma_get_peak_buffer | 71 | * pcm_rec_dma_get_peak_buffer |
71 | * Data Read/Written within TSP - | 72 | * Data Read/Written within TSP - |
72 | * pcm_callback_more_ready (R) | ||
73 | * pcm_recording (R) | 73 | * pcm_recording (R) |
74 | * | 74 | * |
75 | * States are set _after_ the target's pcm driver is called so that it may | 75 | * States are set _after_ the target's pcm driver is called so that it may |
@@ -78,7 +78,7 @@ | |||
78 | */ | 78 | */ |
79 | 79 | ||
80 | /* the registered callback function to ask for more mp3 data */ | 80 | /* the registered callback function to ask for more mp3 data */ |
81 | volatile pcm_more_callback_type pcm_callback_for_more | 81 | static volatile pcm_play_callback_type pcm_callback_for_more |
82 | SHAREDBSS_ATTR = NULL; | 82 | SHAREDBSS_ATTR = NULL; |
83 | /* PCM playback state */ | 83 | /* PCM playback state */ |
84 | volatile bool pcm_playing SHAREDBSS_ATTR = false; | 84 | volatile bool pcm_playing SHAREDBSS_ATTR = false; |
@@ -91,6 +91,14 @@ unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT; | |||
91 | /* samplerate frequency selection index */ | 91 | /* samplerate frequency selection index */ |
92 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; | 92 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; |
93 | 93 | ||
94 | /* Called internally by functions to reset the state */ | ||
95 | static void pcm_play_stopped(void) | ||
96 | { | ||
97 | pcm_callback_for_more = NULL; | ||
98 | pcm_paused = false; | ||
99 | pcm_playing = false; | ||
100 | } | ||
101 | |||
94 | /** | 102 | /** |
95 | * Perform peak calculation on a buffer of packed 16-bit samples. | 103 | * Perform peak calculation on a buffer of packed 16-bit samples. |
96 | * | 104 | * |
@@ -187,6 +195,16 @@ const void* pcm_get_peak_buffer(int * count) | |||
187 | return pcm_play_dma_get_peak_buffer(count); | 195 | return pcm_play_dma_get_peak_buffer(count); |
188 | } | 196 | } |
189 | 197 | ||
198 | bool pcm_is_playing(void) | ||
199 | { | ||
200 | return pcm_playing; | ||
201 | } | ||
202 | |||
203 | bool pcm_is_paused(void) | ||
204 | { | ||
205 | return pcm_paused; | ||
206 | } | ||
207 | |||
190 | /**************************************************************************** | 208 | /**************************************************************************** |
191 | * Functions that do not require targeted implementation but only a targeted | 209 | * Functions that do not require targeted implementation but only a targeted |
192 | * interface | 210 | * interface |
@@ -198,7 +216,7 @@ void pcm_init(void) | |||
198 | { | 216 | { |
199 | logf("pcm_init"); | 217 | logf("pcm_init"); |
200 | 218 | ||
201 | pcm_play_dma_stopped_callback(); | 219 | pcm_play_stopped(); |
202 | 220 | ||
203 | pcm_set_frequency(HW_SAMPR_DEFAULT); | 221 | pcm_set_frequency(HW_SAMPR_DEFAULT); |
204 | 222 | ||
@@ -214,7 +232,7 @@ static void pcm_play_data_start(unsigned char *start, size_t size) | |||
214 | 232 | ||
215 | if (!(start && size)) | 233 | if (!(start && size)) |
216 | { | 234 | { |
217 | pcm_more_callback_type get_more = pcm_callback_for_more; | 235 | pcm_play_callback_type get_more = pcm_callback_for_more; |
218 | size = 0; | 236 | size = 0; |
219 | if (get_more) | 237 | if (get_more) |
220 | { | 238 | { |
@@ -239,10 +257,10 @@ static void pcm_play_data_start(unsigned char *start, size_t size) | |||
239 | /* Force a stop */ | 257 | /* Force a stop */ |
240 | logf(" pcm_play_dma_stop"); | 258 | logf(" pcm_play_dma_stop"); |
241 | pcm_play_dma_stop(); | 259 | pcm_play_dma_stop(); |
242 | pcm_play_dma_stopped_callback(); | 260 | pcm_play_stopped(); |
243 | } | 261 | } |
244 | 262 | ||
245 | void pcm_play_data(pcm_more_callback_type get_more, | 263 | void pcm_play_data(pcm_play_callback_type get_more, |
246 | unsigned char *start, size_t size) | 264 | unsigned char *start, size_t size) |
247 | { | 265 | { |
248 | logf("pcm_play_data"); | 266 | logf("pcm_play_data"); |
@@ -257,6 +275,29 @@ void pcm_play_data(pcm_more_callback_type get_more, | |||
257 | pcm_play_unlock(); | 275 | pcm_play_unlock(); |
258 | } | 276 | } |
259 | 277 | ||
278 | void pcm_play_get_more_callback(void **start, size_t *size) | ||
279 | { | ||
280 | pcm_play_callback_type get_more = pcm_callback_for_more; | ||
281 | |||
282 | *size = 0; | ||
283 | |||
284 | if (get_more && start) | ||
285 | { | ||
286 | /* Call registered callback */ | ||
287 | get_more((unsigned char **)start, size); | ||
288 | |||
289 | *start = (void *)(((uintptr_t)*start + 3) & ~3); | ||
290 | *size &= ~3; | ||
291 | |||
292 | if (*start && *size) | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | /* Error, callback missing or no more DMA to do */ | ||
297 | pcm_play_dma_stop(); | ||
298 | pcm_play_stopped(); | ||
299 | } | ||
300 | |||
260 | void pcm_play_pause(bool play) | 301 | void pcm_play_pause(bool play) |
261 | { | 302 | { |
262 | logf("pcm_play_pause: %s", play ? "play" : "pause"); | 303 | logf("pcm_play_pause: %s", play ? "play" : "pause"); |
@@ -302,7 +343,7 @@ void pcm_play_stop(void) | |||
302 | { | 343 | { |
303 | logf(" pcm_play_dma_stop"); | 344 | logf(" pcm_play_dma_stop"); |
304 | pcm_play_dma_stop(); | 345 | pcm_play_dma_stop(); |
305 | pcm_play_dma_stopped_callback(); | 346 | pcm_play_stopped(); |
306 | } | 347 | } |
307 | else | 348 | else |
308 | { | 349 | { |
@@ -312,13 +353,6 @@ void pcm_play_stop(void) | |||
312 | pcm_play_unlock(); | 353 | pcm_play_unlock(); |
313 | } | 354 | } |
314 | 355 | ||
315 | void pcm_play_dma_stopped_callback(void) | ||
316 | { | ||
317 | pcm_callback_for_more = NULL; | ||
318 | pcm_paused = false; | ||
319 | pcm_playing = false; | ||
320 | } | ||
321 | |||
322 | /**/ | 356 | /**/ |
323 | 357 | ||
324 | /* set frequency next frequency used by the audio hardware - | 358 | /* set frequency next frequency used by the audio hardware - |
@@ -350,27 +384,24 @@ void pcm_apply_settings(void) | |||
350 | } | 384 | } |
351 | } | 385 | } |
352 | 386 | ||
353 | bool pcm_is_playing(void) | ||
354 | { | ||
355 | return pcm_playing; | ||
356 | } | ||
357 | |||
358 | bool pcm_is_paused(void) | ||
359 | { | ||
360 | return pcm_paused; | ||
361 | } | ||
362 | |||
363 | #ifdef HAVE_RECORDING | 387 | #ifdef HAVE_RECORDING |
364 | /** Low level pcm recording apis **/ | 388 | /** Low level pcm recording apis **/ |
365 | 389 | ||
366 | /* Next start for recording peaks */ | 390 | /* Next start for recording peaks */ |
367 | static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR = NULL; | 391 | static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR = NULL; |
368 | /* the registered callback function for when more data is available */ | 392 | /* the registered callback function for when more data is available */ |
369 | volatile pcm_more_callback_type2 | 393 | static volatile pcm_rec_callback_type |
370 | pcm_callback_more_ready SHAREDBSS_ATTR = NULL; | 394 | pcm_callback_more_ready SHAREDBSS_ATTR = NULL; |
371 | /* DMA transfer in is currently active */ | 395 | /* DMA transfer in is currently active */ |
372 | volatile bool pcm_recording SHAREDBSS_ATTR = false; | 396 | volatile bool pcm_recording SHAREDBSS_ATTR = false; |
373 | 397 | ||
398 | /* Called internally by functions to reset the state */ | ||
399 | static void pcm_recording_stopped(void) | ||
400 | { | ||
401 | pcm_recording = false; | ||
402 | pcm_callback_more_ready = NULL; | ||
403 | } | ||
404 | |||
374 | /** | 405 | /** |
375 | * Return recording peaks - From the end of the last peak up to | 406 | * Return recording peaks - From the end of the last peak up to |
376 | * current write position. | 407 | * current write position. |
@@ -410,10 +441,16 @@ void pcm_calculate_rec_peaks(int *left, int *right) | |||
410 | *right = peaks[1]; | 441 | *right = peaks[1]; |
411 | } /* pcm_calculate_rec_peaks */ | 442 | } /* pcm_calculate_rec_peaks */ |
412 | 443 | ||
444 | bool pcm_is_recording(void) | ||
445 | { | ||
446 | return pcm_recording; | ||
447 | } | ||
448 | |||
413 | /**************************************************************************** | 449 | /**************************************************************************** |
414 | * Functions that do not require targeted implementation but only a targeted | 450 | * Functions that do not require targeted implementation but only a targeted |
415 | * interface | 451 | * interface |
416 | */ | 452 | */ |
453 | |||
417 | void pcm_init_recording(void) | 454 | void pcm_init_recording(void) |
418 | { | 455 | { |
419 | logf("pcm_init_recording"); | 456 | logf("pcm_init_recording"); |
@@ -424,7 +461,7 @@ void pcm_init_recording(void) | |||
424 | pcm_rec_lock(); | 461 | pcm_rec_lock(); |
425 | 462 | ||
426 | logf(" pcm_rec_dma_init"); | 463 | logf(" pcm_rec_dma_init"); |
427 | pcm_rec_dma_stopped_callback(); | 464 | pcm_recording_stopped(); |
428 | pcm_rec_dma_init(); | 465 | pcm_rec_dma_init(); |
429 | 466 | ||
430 | pcm_rec_unlock(); | 467 | pcm_rec_unlock(); |
@@ -440,7 +477,7 @@ void pcm_close_recording(void) | |||
440 | { | 477 | { |
441 | logf(" pcm_rec_dma_stop"); | 478 | logf(" pcm_rec_dma_stop"); |
442 | pcm_rec_dma_stop(); | 479 | pcm_rec_dma_stop(); |
443 | pcm_rec_dma_stopped_callback(); | 480 | pcm_recording_stopped(); |
444 | } | 481 | } |
445 | 482 | ||
446 | logf(" pcm_rec_dma_close"); | 483 | logf(" pcm_rec_dma_close"); |
@@ -449,7 +486,7 @@ void pcm_close_recording(void) | |||
449 | pcm_rec_unlock(); | 486 | pcm_rec_unlock(); |
450 | } | 487 | } |
451 | 488 | ||
452 | void pcm_record_data(pcm_more_callback_type2 more_ready, | 489 | void pcm_record_data(pcm_rec_callback_type more_ready, |
453 | void *start, size_t size) | 490 | void *start, size_t size) |
454 | { | 491 | { |
455 | logf("pcm_record_data"); | 492 | logf("pcm_record_data"); |
@@ -493,43 +530,40 @@ void pcm_stop_recording(void) | |||
493 | { | 530 | { |
494 | logf(" pcm_rec_dma_stop"); | 531 | logf(" pcm_rec_dma_stop"); |
495 | pcm_rec_dma_stop(); | 532 | pcm_rec_dma_stop(); |
496 | pcm_rec_dma_stopped_callback(); | 533 | pcm_recording_stopped(); |
497 | } | 534 | } |
498 | 535 | ||
499 | pcm_rec_unlock(); | 536 | pcm_rec_unlock(); |
500 | } /* pcm_stop_recording */ | 537 | } /* pcm_stop_recording */ |
501 | 538 | ||
502 | void pcm_record_more(void *start, size_t size) | 539 | void pcm_rec_more_ready_callback(int status, void **start, size_t *size) |
503 | { | 540 | { |
504 | start = (void *)(((uintptr_t)start + 3) & ~3); | 541 | pcm_rec_callback_type have_more = pcm_callback_more_ready; |
505 | size = size & ~3; | ||
506 | |||
507 | if (!size) | ||
508 | { | ||
509 | pcm_rec_dma_stop(); | ||
510 | pcm_rec_dma_stopped_callback(); | ||
511 | return; | ||
512 | } | ||
513 | 542 | ||
514 | #ifdef HAVE_PCM_REC_DMA_ADDRESS | 543 | *size = 0; |
515 | /* Need a physical DMA address translation, if not already physical. */ | ||
516 | pcm_rec_peak_addr = pcm_dma_addr(start); | ||
517 | #else | ||
518 | pcm_rec_peak_addr = start; | ||
519 | #endif | ||
520 | 544 | ||
521 | pcm_rec_dma_record_more(start, size); | 545 | if (have_more && start) |
522 | } | 546 | { |
547 | have_more(status, start, size); | ||
548 | *start = (void *)(((uintptr_t)*start + 3) & ~3); | ||
549 | *size &= ~3; | ||
523 | 550 | ||
524 | bool pcm_is_recording(void) | 551 | if (*start && *size) |
525 | { | 552 | { |
526 | return pcm_recording; | 553 | #ifdef HAVE_PCM_REC_DMA_ADDRESS |
527 | } | 554 | /* Need a physical DMA address translation, if not already |
555 | * physical. */ | ||
556 | pcm_rec_peak_addr = pcm_dma_addr(*start); | ||
557 | #else | ||
558 | pcm_rec_peak_addr = *start; | ||
559 | #endif | ||
560 | return; | ||
561 | } | ||
562 | } | ||
528 | 563 | ||
529 | void pcm_rec_dma_stopped_callback(void) | 564 | /* Error, callback missing or no more DMA to do */ |
530 | { | 565 | pcm_rec_dma_stop(); |
531 | pcm_recording = false; | 566 | pcm_recording_stopped(); |
532 | pcm_callback_more_ready = NULL; | ||
533 | } | 567 | } |
534 | 568 | ||
535 | #endif /* HAVE_RECORDING */ | 569 | #endif /* HAVE_RECORDING */ |