1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
25 /* Define LOGF_ENABLE to enable logf output in this file */
26 /*#define LOGF_ENABLE*/
31 #include "pcm-internal.h"
32 #include "pcm_mixer.h"
35 * Aspects implemented in the target-specific portion:
40 * pcm_get_bytes_waiting
44 * pcm_play_get_more_callback
46 * pcm_play_dma_postinit
50 * pcm_play_dma_get_peak_buffer
51 * Data Read/Written within TSP -
58 * ==Playback/Recording==
62 * pcm_dma_apply_settings
69 * pcm_rec_more_ready_callback
74 * pcm_rec_dma_get_peak_buffer
75 * Data Read/Written within TSP -
78 * States are set _after_ the target's pcm driver is called so that it may
79 * know from whence the state is changed. One exception is init.
83 /* 'true' when all stages of pcm initialization have completed */
84 static bool pcm_is_ready
= false;
86 /* the registered callback function to ask for more mp3 data */
87 static pcm_play_callback_type pcm_callback_for_more SHAREDBSS_ATTR
= NULL
;
88 void (* pcm_play_dma_started
)(void) SHAREDBSS_ATTR
= NULL
;
89 /* PCM playback state */
90 volatile bool pcm_playing SHAREDBSS_ATTR
= false;
91 /* PCM paused state. paused implies playing */
92 volatile bool pcm_paused SHAREDBSS_ATTR
= false;
93 /* samplerate of currently playing audio - undefined if stopped */
94 unsigned long pcm_curr_sampr SHAREDBSS_ATTR
= 0;
95 /* samplerate waiting to be set */
96 unsigned long pcm_sampr SHAREDBSS_ATTR
= HW_SAMPR_DEFAULT
;
97 /* samplerate frequency selection index */
98 int pcm_fsel SHAREDBSS_ATTR
= HW_FREQ_DEFAULT
;
100 /* peak data for the global peak values - i.e. what the final output is */
101 static struct pcm_peaks global_peaks
;
103 /* Called internally by functions to reset the state */
104 static void pcm_play_stopped(void)
106 pcm_callback_for_more
= NULL
;
107 pcm_play_dma_started
= NULL
;
112 static void pcm_wait_for_init(void)
114 while (!pcm_is_ready
)
119 * Perform peak calculation on a buffer of packed 16-bit samples.
121 * Used for recording and playback.
123 static void pcm_peak_peeker(const int32_t *addr
, int count
, uint16_t peaks
[2])
125 int peak_l
= 0, peak_r
= 0;
126 const int32_t * const end
= addr
+ count
;
130 int32_t value
= *addr
;
133 #ifdef ROCKBOX_BIG_ENDIAN
143 #ifdef ROCKBOX_BIG_ENDIAN
161 void pcm_do_peak_calculation(struct pcm_peaks
*peaks
, bool active
,
162 const void *addr
, int count
)
164 long tick
= current_tick
;
166 /* Peak no farther ahead than expected period to avoid overcalculation */
167 long period
= tick
- peaks
->tick
;
169 /* Keep reasonable limits on period */
172 else if (period
> HZ
/5)
175 peaks
->period
= (3*peaks
->period
+ period
) >> 2;
180 int framecount
= peaks
->period
*pcm_curr_sampr
/ HZ
;
181 count
= MIN(framecount
, count
);
184 pcm_peak_peeker((int32_t *)addr
, count
, peaks
->val
);
185 /* else keep previous peak values */
190 peaks
->val
[0] = peaks
->val
[1] = 0;
194 void pcm_calculate_peaks(int *left
, int *right
)
197 const void *addr
= pcm_play_dma_get_peak_buffer(&count
);
199 pcm_do_peak_calculation(&global_peaks
, pcm_playing
&& !pcm_paused
,
203 *left
= global_peaks
.val
[0];
206 *right
= global_peaks
.val
[1];
209 const void* pcm_get_peak_buffer(int * count
)
211 return pcm_play_dma_get_peak_buffer(count
);
214 bool pcm_is_playing(void)
219 bool pcm_is_paused(void)
224 /****************************************************************************
225 * Functions that do not require targeted implementation but only a targeted
229 /* This should only be called at startup before any audio playback or
230 recording is attempted */
237 pcm_set_frequency(HW_SAMPR_DEFAULT
);
239 logf(" pcm_play_dma_init");
243 /* Finish delayed init */
244 void pcm_postinit(void)
246 logf("pcm_postinit");
248 logf(" pcm_play_dma_postinit");
250 pcm_play_dma_postinit();
255 bool pcm_is_initialized(void)
260 /* Common code to pcm_play_data and pcm_play_pause */
261 static void pcm_play_data_start(unsigned char *start
, size_t size
)
263 start
= (unsigned char *)(((uintptr_t)start
+ 3) & ~3);
266 if (!(start
&& size
))
268 pcm_play_callback_type get_more
= pcm_callback_for_more
;
273 get_more(&start
, &size
);
275 start
= (unsigned char *)(((uintptr_t)start
+ 3) & ~3);
282 logf(" pcm_play_dma_start");
283 pcm_apply_settings();
284 pcm_play_dma_start(start
, size
);
291 logf(" pcm_play_dma_stop");
296 void pcm_play_data(pcm_play_callback_type get_more
,
297 unsigned char *start
, size_t size
)
299 logf("pcm_play_data");
303 pcm_callback_for_more
= get_more
;
305 logf(" pcm_play_data_start");
306 pcm_play_data_start(start
, size
);
311 void pcm_play_get_more_callback(void **start
, size_t *size
)
313 pcm_play_callback_type get_more
= pcm_callback_for_more
;
317 if (get_more
&& start
)
319 /* Call registered callback */
320 get_more((unsigned char **)start
, size
);
322 *start
= (void *)(((uintptr_t)*start
+ 3) & ~3);
329 /* Error, callback missing or no more DMA to do */
334 void pcm_play_pause(bool play
)
336 logf("pcm_play_pause: %s", play
? "play" : "pause");
340 if (play
== pcm_paused
&& pcm_playing
)
344 logf(" pcm_play_dma_pause");
345 pcm_play_dma_pause(true);
348 else if (pcm_get_bytes_waiting() > 0)
350 logf(" pcm_play_dma_pause");
351 pcm_apply_settings();
352 pcm_play_dma_pause(false);
357 logf(" pcm_play_dma_start: no data");
358 pcm_play_data_start(NULL
, 0);
369 void pcm_play_stop(void)
371 logf("pcm_play_stop");
377 logf(" pcm_play_dma_stop");
383 logf(" not playing");
391 /* set frequency next frequency used by the audio hardware -
392 * what pcm_apply_settings will set */
393 void pcm_set_frequency(unsigned int samplerate
)
395 logf("pcm_set_frequency");
399 #ifdef CONFIG_SAMPR_TYPES
400 #ifdef HAVE_RECORDING
401 unsigned int type
= samplerate
& SAMPR_TYPE_MASK
;
403 samplerate
&= ~SAMPR_TYPE_MASK
;
405 #ifdef HAVE_RECORDING
406 #if SAMPR_TYPE_REC != 0
407 /* For now, supported targets have direct conversion when configured with
408 * CONFIG_SAMPR_TYPES.
409 * Some hypothetical target with independent rates would need slightly
410 * different handling throughout this source. */
411 if (type
== SAMPR_TYPE_REC
)
412 samplerate
= pcm_sampr_type_rec_to_play(samplerate
);
414 #endif /* HAVE_RECORDING */
415 #endif /* CONFIG_SAMPR_TYPES */
417 index
= round_value_to_list32(samplerate
, hw_freq_sampr
,
420 if (samplerate
!= hw_freq_sampr
[index
])
421 index
= HW_FREQ_DEFAULT
; /* Invalid = default */
423 pcm_sampr
= hw_freq_sampr
[index
];
427 /* apply pcm settings to the hardware */
428 void pcm_apply_settings(void)
430 logf("pcm_apply_settings");
434 if (pcm_sampr
!= pcm_curr_sampr
)
436 logf(" pcm_dma_apply_settings");
437 pcm_dma_apply_settings();
438 pcm_curr_sampr
= pcm_sampr
;
442 /* register callback to buffer more data */
443 void pcm_play_set_dma_started_callback(void (* callback
)(void))
445 pcm_play_dma_started
= callback
;
448 #ifdef HAVE_RECORDING
449 /** Low level pcm recording apis **/
451 /* Next start for recording peaks */
452 static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR
= NULL
;
453 /* the registered callback function for when more data is available */
454 static volatile pcm_rec_callback_type
455 pcm_callback_more_ready SHAREDBSS_ATTR
= NULL
;
456 /* DMA transfer in is currently active */
457 volatile bool pcm_recording SHAREDBSS_ATTR
= false;
459 /* Called internally by functions to reset the state */
460 static void pcm_recording_stopped(void)
462 pcm_recording
= false;
463 pcm_callback_more_ready
= NULL
;
467 * Return recording peaks - From the end of the last peak up to
468 * current write position.
470 void pcm_calculate_rec_peaks(int *left
, int *right
)
472 static uint16_t peaks
[2];
476 const void *peak_addr
= pcm_rec_peak_addr
;
477 const void *addr
= pcm_rec_dma_get_peak_buffer();
481 int count
= (int)(((intptr_t)addr
- (intptr_t)peak_addr
) >> 2);
485 pcm_peak_peeker((int32_t *)peak_addr
, count
, peaks
);
487 if (peak_addr
== pcm_rec_peak_addr
)
488 pcm_rec_peak_addr
= addr
;
491 /* else keep previous peak values */
495 peaks
[0] = peaks
[1] = 0;
503 } /* pcm_calculate_rec_peaks */
505 bool pcm_is_recording(void)
507 return pcm_recording
;
510 /****************************************************************************
511 * Functions that do not require targeted implementation but only a targeted
515 void pcm_init_recording(void)
517 logf("pcm_init_recording");
521 /* Stop the beasty before attempting recording */
524 /* Recording init is locked unlike general pcm init since this is not
525 * just a one-time event at startup and it should and must be safe by
529 logf(" pcm_rec_dma_init");
530 pcm_recording_stopped();
536 void pcm_close_recording(void)
538 logf("pcm_close_recording");
544 logf(" pcm_rec_dma_stop");
546 pcm_recording_stopped();
549 logf(" pcm_rec_dma_close");
555 void pcm_record_data(pcm_rec_callback_type more_ready
,
556 void *start
, size_t size
)
558 logf("pcm_record_data");
560 /* 32-bit aligned and sized data only */
561 start
= (void *)(((uintptr_t)start
+ 3) & ~3);
564 if (!(start
&& size
))
572 pcm_callback_more_ready
= more_ready
;
574 #ifdef HAVE_PCM_REC_DMA_ADDRESS
575 /* Need a physical DMA address translation, if not already physical. */
576 pcm_rec_peak_addr
= pcm_dma_addr(start
);
578 pcm_rec_peak_addr
= start
;
581 logf(" pcm_rec_dma_start");
582 pcm_apply_settings();
583 pcm_rec_dma_start(start
, size
);
584 pcm_recording
= true;
587 } /* pcm_record_data */
589 void pcm_stop_recording(void)
591 logf("pcm_stop_recording");
597 logf(" pcm_rec_dma_stop");
599 pcm_recording_stopped();
603 } /* pcm_stop_recording */
605 void pcm_rec_more_ready_callback(int status
, void **start
, size_t *size
)
607 pcm_rec_callback_type have_more
= pcm_callback_more_ready
;
611 if (have_more
&& start
)
613 have_more(status
, start
, size
);
614 *start
= (void *)(((uintptr_t)*start
+ 3) & ~3);
619 #ifdef HAVE_PCM_REC_DMA_ADDRESS
620 /* Need a physical DMA address translation, if not already
622 pcm_rec_peak_addr
= pcm_dma_addr(*start
);
624 pcm_rec_peak_addr
= *start
;
630 /* Error, callback missing or no more DMA to do */
632 pcm_recording_stopped();
635 #endif /* HAVE_RECORDING */