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*/
33 * Aspects implemented in the target-specific portion:
38 * pcm_get_bytes_waiting
42 * pcm_play_get_more_callback
47 * pcm_play_dma_get_peak_buffer
48 * Data Read/Written within TSP -
55 * ==Playback/Recording==
59 * pcm_dma_apply_settings
66 * pcm_rec_more_ready_callback
71 * pcm_rec_dma_get_peak_buffer
72 * Data Read/Written within TSP -
75 * States are set _after_ the target's pcm driver is called so that it may
76 * know from whence the state is changed. One exception is init.
80 /* the registered callback function to ask for more mp3 data */
81 static volatile pcm_play_callback_type pcm_callback_for_more
82 SHAREDBSS_ATTR
= NULL
;
83 /* PCM playback state */
84 volatile bool pcm_playing SHAREDBSS_ATTR
= false;
85 /* PCM paused state. paused implies playing */
86 volatile bool pcm_paused SHAREDBSS_ATTR
= false;
87 /* samplerate of currently playing audio - undefined if stopped */
88 unsigned long pcm_curr_sampr SHAREDBSS_ATTR
= 0;
89 /* samplerate waiting to be set */
90 unsigned long pcm_sampr SHAREDBSS_ATTR
= HW_SAMPR_DEFAULT
;
91 /* samplerate frequency selection index */
92 int pcm_fsel SHAREDBSS_ATTR
= HW_FREQ_DEFAULT
;
94 /* Called internally by functions to reset the state */
95 static void pcm_play_stopped(void)
97 pcm_callback_for_more
= NULL
;
103 * Perform peak calculation on a buffer of packed 16-bit samples.
105 * Used for recording and playback.
107 static void pcm_peak_peeker(const int32_t *addr
, int count
, int peaks
[2])
109 int peak_l
= 0, peak_r
= 0;
110 const int32_t * const end
= addr
+ count
;
114 int32_t value
= *addr
;
117 #ifdef ROCKBOX_BIG_ENDIAN
127 #ifdef ROCKBOX_BIG_ENDIAN
145 void pcm_calculate_peaks(int *left
, int *right
)
147 static int peaks
[2] = { 0, 0 };
148 static unsigned long last_peak_tick
= 0;
149 static unsigned long frame_period
= 0;
151 long tick
= current_tick
;
155 /* Throttled peak ahead based on calling period */
156 long period
= tick
- last_peak_tick
;
158 /* Keep reasonable limits on period */
161 else if (period
> HZ
/5)
164 frame_period
= (3*frame_period
+ period
) >> 2;
166 last_peak_tick
= tick
;
168 addr
= pcm_play_dma_get_peak_buffer(&count
);
170 if (pcm_playing
&& !pcm_paused
)
174 framecount
= frame_period
*pcm_curr_sampr
/ HZ
;
175 count
= MIN(framecount
, count
);
178 pcm_peak_peeker((int32_t *)addr
, count
, peaks
);
179 /* else keep previous peak values */
183 peaks
[0] = peaks
[1] = 0;
193 const void* pcm_get_peak_buffer(int * count
)
195 return pcm_play_dma_get_peak_buffer(count
);
198 bool pcm_is_playing(void)
203 bool pcm_is_paused(void)
208 /****************************************************************************
209 * Functions that do not require targeted implementation but only a targeted
213 /* This should only be called at startup before any audio playback or
214 recording is attempted */
221 pcm_set_frequency(HW_SAMPR_DEFAULT
);
223 logf(" pcm_play_dma_init");
227 /* Common code to pcm_play_data and pcm_play_pause */
228 static void pcm_play_data_start(unsigned char *start
, size_t size
)
230 start
= (unsigned char *)(((uintptr_t)start
+ 3) & ~3);
233 if (!(start
&& size
))
235 pcm_play_callback_type get_more
= pcm_callback_for_more
;
240 get_more(&start
, &size
);
242 start
= (unsigned char *)(((uintptr_t)start
+ 3) & ~3);
249 logf(" pcm_play_dma_start");
250 pcm_apply_settings();
251 pcm_play_dma_start(start
, size
);
258 logf(" pcm_play_dma_stop");
263 void pcm_play_data(pcm_play_callback_type get_more
,
264 unsigned char *start
, size_t size
)
266 logf("pcm_play_data");
270 pcm_callback_for_more
= get_more
;
272 logf(" pcm_play_data_start");
273 pcm_play_data_start(start
, size
);
278 void pcm_play_get_more_callback(void **start
, size_t *size
)
280 pcm_play_callback_type get_more
= pcm_callback_for_more
;
284 if (get_more
&& start
)
286 /* Call registered callback */
287 get_more((unsigned char **)start
, size
);
289 *start
= (void *)(((uintptr_t)*start
+ 3) & ~3);
296 /* Error, callback missing or no more DMA to do */
301 void pcm_play_pause(bool play
)
303 logf("pcm_play_pause: %s", play
? "play" : "pause");
307 if (play
== pcm_paused
&& pcm_playing
)
311 logf(" pcm_play_dma_pause");
312 pcm_play_dma_pause(true);
315 else if (pcm_get_bytes_waiting() > 0)
317 logf(" pcm_play_dma_pause");
318 pcm_apply_settings();
319 pcm_play_dma_pause(false);
324 logf(" pcm_play_dma_start: no data");
325 pcm_play_data_start(NULL
, 0);
336 void pcm_play_stop(void)
338 logf("pcm_play_stop");
344 logf(" pcm_play_dma_stop");
350 logf(" not playing");
358 /* set frequency next frequency used by the audio hardware -
359 * what pcm_apply_settings will set */
360 void pcm_set_frequency(unsigned int samplerate
)
362 logf("pcm_set_frequency");
366 #ifdef CONFIG_SAMPR_TYPES
367 #ifdef HAVE_RECORDING
368 unsigned int type
= samplerate
& SAMPR_TYPE_MASK
;
370 samplerate
&= ~SAMPR_TYPE_MASK
;
372 #ifdef HAVE_RECORDING
373 #if SAMPR_TYPE_REC != 0
374 /* For now, supported targets have direct conversion when configured with
375 * CONFIG_SAMPR_TYPES.
376 * Some hypothetical target with independent rates would need slightly
377 * different handling throughout this source. */
378 if (type
== SAMPR_TYPE_REC
)
379 samplerate
= pcm_sampr_type_rec_to_play(samplerate
);
381 #endif /* HAVE_RECORDING */
382 #endif /* CONFIG_SAMPR_TYPES */
384 index
= round_value_to_list32(samplerate
, hw_freq_sampr
,
387 if (samplerate
!= hw_freq_sampr
[index
])
388 index
= HW_FREQ_DEFAULT
; /* Invalid = default */
390 pcm_sampr
= hw_freq_sampr
[index
];
394 /* apply pcm settings to the hardware */
395 void pcm_apply_settings(void)
397 logf("pcm_apply_settings");
399 if (pcm_sampr
!= pcm_curr_sampr
)
401 logf(" pcm_dma_apply_settings");
402 pcm_dma_apply_settings();
403 pcm_curr_sampr
= pcm_sampr
;
407 #ifdef HAVE_RECORDING
408 /** Low level pcm recording apis **/
410 /* Next start for recording peaks */
411 static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR
= NULL
;
412 /* the registered callback function for when more data is available */
413 static volatile pcm_rec_callback_type
414 pcm_callback_more_ready SHAREDBSS_ATTR
= NULL
;
415 /* DMA transfer in is currently active */
416 volatile bool pcm_recording SHAREDBSS_ATTR
= false;
418 /* Called internally by functions to reset the state */
419 static void pcm_recording_stopped(void)
421 pcm_recording
= false;
422 pcm_callback_more_ready
= NULL
;
426 * Return recording peaks - From the end of the last peak up to
427 * current write position.
429 void pcm_calculate_rec_peaks(int *left
, int *right
)
435 const void *peak_addr
= pcm_rec_peak_addr
;
436 const void *addr
= pcm_rec_dma_get_peak_buffer();
440 int count
= (int)(((intptr_t)addr
- (intptr_t)peak_addr
) >> 2);
444 pcm_peak_peeker((int32_t *)peak_addr
, count
, peaks
);
446 if (peak_addr
== pcm_rec_peak_addr
)
447 pcm_rec_peak_addr
= addr
;
450 /* else keep previous peak values */
454 peaks
[0] = peaks
[1] = 0;
462 } /* pcm_calculate_rec_peaks */
464 bool pcm_is_recording(void)
466 return pcm_recording
;
469 /****************************************************************************
470 * Functions that do not require targeted implementation but only a targeted
474 void pcm_init_recording(void)
476 logf("pcm_init_recording");
478 /* Recording init is locked unlike general pcm init since this is not
479 * just a one-time event at startup and it should and must be safe by
483 logf(" pcm_rec_dma_init");
484 pcm_recording_stopped();
490 void pcm_close_recording(void)
492 logf("pcm_close_recording");
498 logf(" pcm_rec_dma_stop");
500 pcm_recording_stopped();
503 logf(" pcm_rec_dma_close");
509 void pcm_record_data(pcm_rec_callback_type more_ready
,
510 void *start
, size_t size
)
512 logf("pcm_record_data");
514 /* 32-bit aligned and sized data only */
515 start
= (void *)(((uintptr_t)start
+ 3) & ~3);
518 if (!(start
&& size
))
526 pcm_callback_more_ready
= more_ready
;
528 #ifdef HAVE_PCM_REC_DMA_ADDRESS
529 /* Need a physical DMA address translation, if not already physical. */
530 pcm_rec_peak_addr
= pcm_dma_addr(start
);
532 pcm_rec_peak_addr
= start
;
535 logf(" pcm_rec_dma_start");
536 pcm_apply_settings();
537 pcm_rec_dma_start(start
, size
);
538 pcm_recording
= true;
541 } /* pcm_record_data */
543 void pcm_stop_recording(void)
545 logf("pcm_stop_recording");
551 logf(" pcm_rec_dma_stop");
553 pcm_recording_stopped();
557 } /* pcm_stop_recording */
559 void pcm_rec_more_ready_callback(int status
, void **start
, size_t *size
)
561 pcm_rec_callback_type have_more
= pcm_callback_more_ready
;
565 if (have_more
&& start
)
567 have_more(status
, start
, size
);
568 *start
= (void *)(((uintptr_t)*start
+ 3) & ~3);
573 #ifdef HAVE_PCM_REC_DMA_ADDRESS
574 /* Need a physical DMA address translation, if not already
576 pcm_rec_peak_addr
= pcm_dma_addr(*start
);
578 pcm_rec_peak_addr
= *start
;
584 /* Error, callback missing or no more DMA to do */
586 pcm_recording_stopped();
589 #endif /* HAVE_RECORDING */