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 ****************************************************************************/
30 * Aspects implemented in the target-specific portion:
35 * pcm_get_bytes_waiting
44 * pcm_play_dma_get_peak_buffer
45 * Data Read/Written within TSP -
49 * pcm_callback_for_more (R)
53 * ==Playback/Recording==
55 * pcm_dma_apply_settings
67 * pcm_rec_dma_get_peak_buffer
68 * Data Read/Written within TSP -
69 * pcm_rec_peak_addr (R/W)
70 * pcm_callback_more_ready (R)
73 * States are set _after_ the target's pcm driver is called so that it may
74 * know from whence the state is changed. One exception is init.
78 /* the registered callback function to ask for more mp3 data */
79 volatile pcm_more_callback_type pcm_callback_for_more
80 SHAREDBSS_ATTR
= NULL
;
81 /* PCM playback state */
82 volatile bool pcm_playing SHAREDBSS_ATTR
= false;
83 /* PCM paused state. paused implies playing */
84 volatile bool pcm_paused SHAREDBSS_ATTR
= false;
85 /* samplerate of currently playing audio - undefined if stopped */
86 unsigned long pcm_curr_sampr SHAREDBSS_ATTR
= 0;
87 /* samplerate waiting to be set */
88 unsigned long pcm_sampr SHAREDBSS_ATTR
= HW_SAMPR_DEFAULT
;
89 /* samplerate frequency selection index */
90 int pcm_fsel SHAREDBSS_ATTR
= HW_FREQ_DEFAULT
;
93 * Do peak calculation using distance squared from axis and save a lot
94 * of jumps and negation. Don't bother with the calculations of left or
95 * right only as it's never really used and won't save much time.
97 * Used for recording and playback.
99 static void pcm_peak_peeker(const void *addr
, int count
, int peaks
[2])
101 int32_t peak_l
= 0, peak_r
= 0;
102 int32_t peaksq_l
= 0, peaksq_r
= 0;
106 int32_t value
= *(int32_t *)addr
;
108 #ifdef ROCKBOX_BIG_ENDIAN
115 peak_l
= ch
, peaksq_l
= chsq
;
117 #ifdef ROCKBOX_BIG_ENDIAN
124 peak_r
= ch
, peaksq_r
= chsq
;
131 peaks
[0] = abs(peak_l
);
132 peaks
[1] = abs(peak_r
);
135 void pcm_calculate_peaks(int *left
, int *right
)
137 static int peaks
[2] = { 0, 0 };
138 static unsigned long last_peak_tick
= 0;
139 static unsigned long frame_period
= 0;
141 long tick
= current_tick
;
145 /* Throttled peak ahead based on calling period */
146 long period
= tick
- last_peak_tick
;
148 /* Keep reasonable limits on period */
151 else if (period
> HZ
/5)
154 frame_period
= (3*frame_period
+ period
) >> 2;
156 last_peak_tick
= tick
;
158 addr
= pcm_play_dma_get_peak_buffer(&count
);
160 if (pcm_playing
&& !pcm_paused
)
164 framecount
= frame_period
*pcm_curr_sampr
/ HZ
;
165 count
= MIN(framecount
, count
);
168 pcm_peak_peeker(addr
, count
, peaks
);
169 /* else keep previous peak values */
173 peaks
[0] = peaks
[1] = 0;
183 /****************************************************************************
184 * Functions that do not require targeted implementation but only a targeted
188 /* This should only be called at startup before any audio playback or
189 recording is attempted */
194 pcm_play_dma_stopped_callback();
196 pcm_set_frequency(HW_SAMPR_DEFAULT
);
198 logf(" pcm_play_dma_init");
202 /* Common code to pcm_play_data and pcm_play_pause */
203 static void pcm_play_data_start(unsigned char *start
, size_t size
)
205 if (!(start
&& size
))
207 pcm_more_callback_type get_more
= pcm_callback_for_more
;
212 get_more(&start
, &size
);
218 logf(" pcm_play_dma_start");
219 pcm_apply_settings();
220 pcm_play_dma_start(start
, size
);
227 logf(" pcm_play_dma_stop");
229 pcm_play_dma_stopped_callback();
232 void pcm_play_data(pcm_more_callback_type get_more
,
233 unsigned char *start
, size_t size
)
235 logf("pcm_play_data");
239 pcm_callback_for_more
= get_more
;
241 logf(" pcm_play_data_start");
242 pcm_play_data_start(start
, size
);
247 void pcm_play_pause(bool play
)
249 logf("pcm_play_pause: %s", play
? "play" : "pause");
253 if (play
== pcm_paused
&& pcm_playing
)
257 logf(" pcm_play_dma_pause");
258 pcm_play_dma_pause(true);
261 else if (pcm_get_bytes_waiting() > 0)
263 logf(" pcm_play_dma_pause");
264 pcm_apply_settings();
265 pcm_play_dma_pause(false);
270 logf(" pcm_play_dma_start: no data");
271 pcm_play_data_start(NULL
, 0);
282 void pcm_play_stop(void)
284 logf("pcm_play_stop");
290 logf(" pcm_play_dma_stop");
292 pcm_play_dma_stopped_callback();
296 logf(" not playing");
302 void pcm_play_dma_stopped_callback(void)
304 pcm_callback_for_more
= NULL
;
311 /* set frequency next frequency used by the audio hardware -
312 * what pcm_apply_settings will set */
313 void pcm_set_frequency(unsigned int samplerate
)
315 logf("pcm_set_frequency");
317 int index
= round_value_to_list32(samplerate
, hw_freq_sampr
,
320 if (samplerate
!= hw_freq_sampr
[index
])
321 index
= HW_FREQ_DEFAULT
; /* Invalid = default */
323 pcm_sampr
= hw_freq_sampr
[index
];
327 /* apply pcm settings to the hardware */
328 void pcm_apply_settings(void)
330 logf("pcm_apply_settings");
332 if (pcm_sampr
!= pcm_curr_sampr
)
334 logf(" pcm_dma_apply_settings");
335 pcm_dma_apply_settings();
336 pcm_curr_sampr
= pcm_sampr
;
340 bool pcm_is_playing(void)
345 bool pcm_is_paused(void)
350 void pcm_mute(bool mute
)
360 #ifdef HAVE_RECORDING
361 /** Low level pcm recording apis **/
363 /* Next start for recording peaks */
364 const volatile void *pcm_rec_peak_addr SHAREDBSS_ATTR
= NULL
;
365 /* the registered callback function for when more data is available */
366 volatile pcm_more_callback_type2
367 pcm_callback_more_ready SHAREDBSS_ATTR
= NULL
;
368 /* DMA transfer in is currently active */
369 volatile bool pcm_recording SHAREDBSS_ATTR
= false;
372 * Return recording peaks - From the end of the last peak up to
373 * current write position.
375 void pcm_calculate_rec_peaks(int *left
, int *right
)
379 const void *addr
= pcm_rec_dma_get_peak_buffer(&count
);
385 pcm_peak_peeker(addr
, count
, peaks
);
387 if (addr
== pcm_rec_peak_addr
)
388 pcm_rec_peak_addr
= (int32_t *)addr
+ count
;
390 /* else keep previous peak values */
394 peaks
[0] = peaks
[1] = 0;
402 } /* pcm_calculate_rec_peaks */
404 /****************************************************************************
405 * Functions that do not require targeted implementation but only a targeted
408 void pcm_init_recording(void)
410 logf("pcm_init_recording");
412 /* Recording init is locked unlike general pcm init since this is not
413 * just a one-time event at startup and it should and must be safe by
417 logf(" pcm_rec_dma_init");
418 pcm_rec_dma_stopped_callback();
424 void pcm_close_recording(void)
426 logf("pcm_close_recording");
432 logf(" pcm_rec_dma_stop");
434 pcm_rec_dma_stopped_callback();
437 logf(" pcm_rec_dma_close");
443 void pcm_record_data(pcm_more_callback_type2 more_ready
,
444 void *start
, size_t size
)
446 logf("pcm_record_data");
448 if (!(start
&& size
))
456 pcm_callback_more_ready
= more_ready
;
458 logf(" pcm_rec_dma_start");
459 pcm_apply_settings();
460 pcm_rec_dma_start(start
, size
);
461 pcm_recording
= true;
464 } /* pcm_record_data */
466 void pcm_stop_recording(void)
468 logf("pcm_stop_recording");
474 logf(" pcm_rec_dma_stop");
476 pcm_rec_dma_stopped_callback();
480 } /* pcm_stop_recording */
482 bool pcm_is_recording(void)
484 return pcm_recording
;
487 void pcm_rec_dma_stopped_callback(void)
489 pcm_recording
= false;
490 pcm_callback_more_ready
= NULL
;
493 #endif /* HAVE_RECORDING */