Fix charcell build
[maemo-rb.git] / firmware / pcm.c
blobb0a91fb64ec8d5d64ae301441ac575c03b0069a8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include <stdlib.h>
22 #include "system.h"
23 #include "kernel.h"
25 /* Define LOGF_ENABLE to enable logf output in this file */
26 /*#define LOGF_ENABLE*/
27 #include "logf.h"
28 #include "audio.h"
29 #include "sound.h"
30 #include "general.h"
31 #include "pcm-internal.h"
32 #include "pcm_mixer.h"
34 /**
35 * Aspects implemented in the target-specific portion:
37 * ==Playback==
38 * Public -
39 * pcm_postinit
40 * pcm_get_bytes_waiting
41 * pcm_play_lock
42 * pcm_play_unlock
43 * Semi-private -
44 * pcm_play_get_more_callback
45 * pcm_play_dma_init
46 * pcm_play_dma_postinit
47 * pcm_play_dma_start
48 * pcm_play_dma_stop
49 * pcm_play_dma_pause
50 * pcm_play_dma_get_peak_buffer
51 * Data Read/Written within TSP -
52 * pcm_sampr (R)
53 * pcm_fsel (R)
54 * pcm_curr_sampr (R)
55 * pcm_playing (R)
56 * pcm_paused (R)
58 * ==Playback/Recording==
59 * Public -
60 * pcm_dma_addr
61 * Semi-private -
62 * pcm_dma_apply_settings
64 * ==Recording==
65 * Public -
66 * pcm_rec_lock
67 * pcm_rec_unlock
68 * Semi-private -
69 * pcm_rec_more_ready_callback
70 * pcm_rec_dma_init
71 * pcm_rec_dma_close
72 * pcm_rec_dma_start
73 * pcm_rec_dma_stop
74 * pcm_rec_dma_get_peak_buffer
75 * Data Read/Written within TSP -
76 * pcm_recording (R)
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;
108 pcm_paused = false;
109 pcm_playing = false;
112 static void pcm_wait_for_init(void)
114 while (!pcm_is_ready)
115 sleep(0);
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;
131 int ch;
133 #ifdef ROCKBOX_BIG_ENDIAN
134 ch = value >> 16;
135 #else
136 ch = (int16_t)value;
137 #endif
138 if (ch < 0)
139 ch = -ch;
140 if (ch > peak_l)
141 peak_l = ch;
143 #ifdef ROCKBOX_BIG_ENDIAN
144 ch = (int16_t)value;
145 #else
146 ch = value >> 16;
147 #endif
148 if (ch < 0)
149 ch = -ch;
150 if (ch > peak_r)
151 peak_r = ch;
153 addr += 4;
155 while (addr < end);
157 peaks[0] = peak_l;
158 peaks[1] = peak_r;
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 */
170 if (period < 1)
171 period = 1;
172 else if (period > HZ/5)
173 period = HZ/5;
175 peaks->period = (3*peaks->period + period) >> 2;
176 peaks->tick = tick;
178 if (active)
180 int framecount = peaks->period*pcm_curr_sampr / HZ;
181 count = MIN(framecount, count);
183 if (count > 0)
184 pcm_peak_peeker((int32_t *)addr, count, peaks->val);
185 /* else keep previous peak values */
187 else
189 /* peaks are zero */
190 peaks->val[0] = peaks->val[1] = 0;
194 void pcm_calculate_peaks(int *left, int *right)
196 int count;
197 const void *addr = pcm_play_dma_get_peak_buffer(&count);
199 pcm_do_peak_calculation(&global_peaks, pcm_playing && !pcm_paused,
200 addr, count);
202 if (left)
203 *left = global_peaks.val[0];
205 if (right)
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)
216 return pcm_playing;
219 bool pcm_is_paused(void)
221 return pcm_paused;
224 /****************************************************************************
225 * Functions that do not require targeted implementation but only a targeted
226 * interface
229 /* This should only be called at startup before any audio playback or
230 recording is attempted */
231 void pcm_init(void)
233 logf("pcm_init");
235 pcm_play_stopped();
237 pcm_set_frequency(HW_SAMPR_DEFAULT);
239 logf(" pcm_play_dma_init");
240 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();
252 pcm_is_ready = true;
255 bool pcm_is_initialized(void)
257 return pcm_is_ready;
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);
264 size &= ~3;
266 if (!(start && size))
268 pcm_play_callback_type get_more = pcm_callback_for_more;
269 size = 0;
270 if (get_more)
272 logf(" get_more");
273 get_more(&start, &size);
275 start = (unsigned char *)(((uintptr_t)start + 3) & ~3);
276 size &= ~3;
280 if (start && size)
282 logf(" pcm_play_dma_start");
283 pcm_apply_settings();
284 pcm_play_dma_start(start, size);
285 pcm_playing = true;
286 pcm_paused = false;
287 return;
290 /* Force a stop */
291 logf(" pcm_play_dma_stop");
292 pcm_play_dma_stop();
293 pcm_play_stopped();
296 void pcm_play_data(pcm_play_callback_type get_more,
297 unsigned char *start, size_t size)
299 logf("pcm_play_data");
301 pcm_play_lock();
303 pcm_callback_for_more = get_more;
305 logf(" pcm_play_data_start");
306 pcm_play_data_start(start, size);
308 pcm_play_unlock();
311 void pcm_play_get_more_callback(void **start, size_t *size)
313 pcm_play_callback_type get_more = pcm_callback_for_more;
315 *size = 0;
317 if (get_more && start)
319 /* Call registered callback */
320 get_more((unsigned char **)start, size);
322 *start = (void *)(((uintptr_t)*start + 3) & ~3);
323 *size &= ~3;
325 if (*start && *size)
326 return;
329 /* Error, callback missing or no more DMA to do */
330 pcm_play_dma_stop();
331 pcm_play_stopped();
334 void pcm_play_pause(bool play)
336 logf("pcm_play_pause: %s", play ? "play" : "pause");
338 pcm_play_lock();
340 if (play == pcm_paused && pcm_playing)
342 if (!play)
344 logf(" pcm_play_dma_pause");
345 pcm_play_dma_pause(true);
346 pcm_paused = 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);
353 pcm_paused = false;
355 else
357 logf(" pcm_play_dma_start: no data");
358 pcm_play_data_start(NULL, 0);
361 else
363 logf(" no change");
366 pcm_play_unlock();
369 void pcm_play_stop(void)
371 logf("pcm_play_stop");
373 pcm_play_lock();
375 if (pcm_playing)
377 logf(" pcm_play_dma_stop");
378 pcm_play_dma_stop();
379 pcm_play_stopped();
381 else
383 logf(" not playing");
386 pcm_play_unlock();
389 /**/
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");
397 int index;
399 #ifdef CONFIG_SAMPR_TYPES
400 #ifdef HAVE_RECORDING
401 unsigned int type = samplerate & SAMPR_TYPE_MASK;
402 #endif
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);
413 #endif
414 #endif /* HAVE_RECORDING */
415 #endif /* CONFIG_SAMPR_TYPES */
417 index = round_value_to_list32(samplerate, hw_freq_sampr,
418 HW_NUM_FREQ, false);
420 if (samplerate != hw_freq_sampr[index])
421 index = HW_FREQ_DEFAULT; /* Invalid = default */
423 pcm_sampr = hw_freq_sampr[index];
424 pcm_fsel = index;
427 /* apply pcm settings to the hardware */
428 void pcm_apply_settings(void)
430 logf("pcm_apply_settings");
432 pcm_wait_for_init();
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];
474 if (pcm_recording)
476 const void *peak_addr = pcm_rec_peak_addr;
477 const void *addr = pcm_rec_dma_get_peak_buffer();
479 if (addr != NULL)
481 int count = (int)(((intptr_t)addr - (intptr_t)peak_addr) >> 2);
483 if (count > 0)
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 */
493 else
495 peaks[0] = peaks[1] = 0;
498 if (left)
499 *left = peaks[0];
501 if (right)
502 *right = peaks[1];
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
512 * interface
515 void pcm_init_recording(void)
517 logf("pcm_init_recording");
519 pcm_wait_for_init();
521 /* Stop the beasty before attempting recording */
522 mixer_reset();
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
526 * now. */
527 pcm_rec_lock();
529 logf(" pcm_rec_dma_init");
530 pcm_recording_stopped();
531 pcm_rec_dma_init();
533 pcm_rec_unlock();
536 void pcm_close_recording(void)
538 logf("pcm_close_recording");
540 pcm_rec_lock();
542 if (pcm_recording)
544 logf(" pcm_rec_dma_stop");
545 pcm_rec_dma_stop();
546 pcm_recording_stopped();
549 logf(" pcm_rec_dma_close");
550 pcm_rec_dma_close();
552 pcm_rec_unlock();
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);
562 size &= ~3;
564 if (!(start && size))
566 logf(" no buffer");
567 return;
570 pcm_rec_lock();
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);
577 #else
578 pcm_rec_peak_addr = start;
579 #endif
581 logf(" pcm_rec_dma_start");
582 pcm_apply_settings();
583 pcm_rec_dma_start(start, size);
584 pcm_recording = true;
586 pcm_rec_unlock();
587 } /* pcm_record_data */
589 void pcm_stop_recording(void)
591 logf("pcm_stop_recording");
593 pcm_rec_lock();
595 if (pcm_recording)
597 logf(" pcm_rec_dma_stop");
598 pcm_rec_dma_stop();
599 pcm_recording_stopped();
602 pcm_rec_unlock();
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;
609 *size = 0;
611 if (have_more && start)
613 have_more(status, start, size);
614 *start = (void *)(((uintptr_t)*start + 3) & ~3);
615 *size &= ~3;
617 if (*start && *size)
619 #ifdef HAVE_PCM_REC_DMA_ADDRESS
620 /* Need a physical DMA address translation, if not already
621 * physical. */
622 pcm_rec_peak_addr = pcm_dma_addr(*start);
623 #else
624 pcm_rec_peak_addr = *start;
625 #endif
626 return;
630 /* Error, callback missing or no more DMA to do */
631 pcm_rec_dma_stop();
632 pcm_recording_stopped();
635 #endif /* HAVE_RECORDING */