brickmania: Disable resuming after game over
[maemo-rb.git] / firmware / pcm.c
blob621ed56e0d3f566cb2ec5dcfea136e6db0cfd29c
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_dma_complete_callback
45 * pcm_play_dma_status_callback
46 * pcm_play_dma_init
47 * pcm_play_dma_postinit
48 * pcm_play_dma_start
49 * pcm_play_dma_stop
50 * pcm_play_dma_pause
51 * pcm_play_dma_get_peak_buffer
52 * Data Read/Written within TSP -
53 * pcm_sampr (R)
54 * pcm_fsel (R)
55 * pcm_curr_sampr (R)
56 * pcm_playing (R)
57 * pcm_paused (R)
59 * ==Playback/Recording==
60 * Public -
61 * pcm_dma_addr
62 * Semi-private -
63 * pcm_dma_apply_settings
65 * ==Recording==
66 * Public -
67 * pcm_rec_lock
68 * pcm_rec_unlock
69 * Semi-private -
70 * pcm_rec_dma_complete_callback
71 * pcm_rec_dma_status_callback
72 * pcm_rec_dma_init
73 * pcm_rec_dma_close
74 * pcm_rec_dma_start
75 * pcm_rec_dma_stop
76 * pcm_rec_dma_get_peak_buffer
77 * Data Read/Written within TSP -
78 * pcm_recording (R)
80 * States are set _after_ the target's pcm driver is called so that it may
81 * know from whence the state is changed. One exception is init.
85 /* 'true' when all stages of pcm initialization have completed */
86 static bool pcm_is_ready = false;
88 /* The registered callback function to ask for more mp3 data */
89 static volatile pcm_play_callback_type
90 pcm_callback_for_more SHAREDBSS_ATTR = NULL;
91 /* The registered callback function to inform of DMA status */
92 volatile pcm_status_callback_type
93 pcm_play_status_callback SHAREDBSS_ATTR = NULL;
94 /* PCM playback state */
95 volatile bool pcm_playing SHAREDBSS_ATTR = false;
96 /* PCM paused state. paused implies playing */
97 volatile bool pcm_paused SHAREDBSS_ATTR = false;
98 /* samplerate of currently playing audio - undefined if stopped */
99 unsigned long pcm_curr_sampr SHAREDBSS_ATTR = 0;
100 /* samplerate waiting to be set */
101 unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
102 /* samplerate frequency selection index */
103 int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
105 /* peak data for the global peak values - i.e. what the final output is */
106 static struct pcm_peaks global_peaks;
108 /* Called internally by functions to reset the state */
109 static void pcm_play_stopped(void)
111 pcm_callback_for_more = NULL;
112 pcm_play_status_callback = NULL;
113 pcm_paused = false;
114 pcm_playing = false;
117 static void pcm_wait_for_init(void)
119 while (!pcm_is_ready)
120 sleep(0);
124 * Perform peak calculation on a buffer of packed 16-bit samples.
126 * Used for recording and playback.
128 static void pcm_peak_peeker(const int32_t *addr, int count, uint16_t peaks[2])
130 int peak_l = 0, peak_r = 0;
131 const int32_t * const end = addr + count;
135 int32_t value = *addr;
136 int ch;
138 #ifdef ROCKBOX_BIG_ENDIAN
139 ch = value >> 16;
140 #else
141 ch = (int16_t)value;
142 #endif
143 if (ch < 0)
144 ch = -ch;
145 if (ch > peak_l)
146 peak_l = ch;
148 #ifdef ROCKBOX_BIG_ENDIAN
149 ch = (int16_t)value;
150 #else
151 ch = value >> 16;
152 #endif
153 if (ch < 0)
154 ch = -ch;
155 if (ch > peak_r)
156 peak_r = ch;
158 addr += 4;
160 while (addr < end);
162 peaks[0] = peak_l;
163 peaks[1] = peak_r;
166 void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
167 const void *addr, int count)
169 long tick = current_tick;
171 /* Peak no farther ahead than expected period to avoid overcalculation */
172 long period = tick - peaks->tick;
174 /* Keep reasonable limits on period */
175 if (period < 1)
176 period = 1;
177 else if (period > HZ/5)
178 period = HZ/5;
180 peaks->period = (3*peaks->period + period) >> 2;
181 peaks->tick = tick;
183 if (active)
185 int framecount = peaks->period*pcm_curr_sampr / HZ;
186 count = MIN(framecount, count);
188 if (count > 0)
189 pcm_peak_peeker((int32_t *)addr, count, peaks->val);
190 /* else keep previous peak values */
192 else
194 /* peaks are zero */
195 peaks->val[0] = peaks->val[1] = 0;
199 void pcm_calculate_peaks(int *left, int *right)
201 int count;
202 const void *addr = pcm_play_dma_get_peak_buffer(&count);
204 pcm_do_peak_calculation(&global_peaks, pcm_playing && !pcm_paused,
205 addr, count);
207 if (left)
208 *left = global_peaks.val[0];
210 if (right)
211 *right = global_peaks.val[1];
214 const void* pcm_get_peak_buffer(int * count)
216 return pcm_play_dma_get_peak_buffer(count);
219 bool pcm_is_playing(void)
221 return pcm_playing;
224 bool pcm_is_paused(void)
226 return pcm_paused;
229 /****************************************************************************
230 * Functions that do not require targeted implementation but only a targeted
231 * interface
234 /* This should only be called at startup before any audio playback or
235 recording is attempted */
236 void pcm_init(void)
238 logf("pcm_init");
240 pcm_play_stopped();
242 pcm_set_frequency(HW_SAMPR_DEFAULT);
244 logf(" pcm_play_dma_init");
245 pcm_play_dma_init();
248 /* Finish delayed init */
249 void pcm_postinit(void)
251 logf("pcm_postinit");
253 logf(" pcm_play_dma_postinit");
255 pcm_play_dma_postinit();
257 pcm_is_ready = true;
260 bool pcm_is_initialized(void)
262 return pcm_is_ready;
265 /* Common code to pcm_play_data and pcm_play_pause */
266 static void pcm_play_data_start(const void *addr, size_t size)
268 ALIGN_AUDIOBUF(addr, size);
270 if (!(addr && size))
272 pcm_play_callback_type get_more = pcm_callback_for_more;
273 addr = NULL;
274 size = 0;
276 if (get_more)
278 logf(" get_more");
279 get_more(&addr, &size);
280 ALIGN_AUDIOBUF(addr, size);
284 if (addr && size)
286 logf(" pcm_play_dma_start");
287 pcm_apply_settings();
288 pcm_play_dma_start(addr, size);
289 pcm_playing = true;
290 pcm_paused = false;
291 return;
294 /* Force a stop */
295 logf(" pcm_play_dma_stop");
296 pcm_play_dma_stop();
297 pcm_play_stopped();
300 void pcm_play_data(pcm_play_callback_type get_more,
301 pcm_status_callback_type status_cb,
302 const void *start, size_t size)
304 logf("pcm_play_data");
306 pcm_play_lock();
308 pcm_callback_for_more = get_more;
309 pcm_play_status_callback = status_cb;
311 logf(" pcm_play_data_start");
312 pcm_play_data_start(start, size);
314 pcm_play_unlock();
317 bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
318 const void **addr, size_t *size)
320 /* Check status callback first if error */
321 if (status < PCM_DMAST_OK)
322 status = pcm_play_dma_status_callback(status);
324 pcm_play_callback_type get_more = pcm_callback_for_more;
326 if (get_more && status >= PCM_DMAST_OK)
328 *addr = NULL;
329 *size = 0;
331 /* Call registered callback to obtain next buffer */
332 get_more(addr, size);
333 ALIGN_AUDIOBUF(*addr, *size);
335 if (*addr && *size)
336 return true;
339 /* Error, callback missing or no more DMA to do */
340 pcm_play_dma_stop();
341 pcm_play_stopped();
343 return false;
346 void pcm_play_pause(bool play)
348 logf("pcm_play_pause: %s", play ? "play" : "pause");
350 pcm_play_lock();
352 if (play == pcm_paused && pcm_playing)
354 if (!play)
356 logf(" pcm_play_dma_pause");
357 pcm_play_dma_pause(true);
358 pcm_paused = true;
360 else if (pcm_get_bytes_waiting() > 0)
362 logf(" pcm_play_dma_pause");
363 pcm_apply_settings();
364 pcm_play_dma_pause(false);
365 pcm_paused = false;
367 else
369 logf(" pcm_play_dma_start: no data");
370 pcm_play_data_start(NULL, 0);
373 else
375 logf(" no change");
378 pcm_play_unlock();
381 void pcm_play_stop(void)
383 logf("pcm_play_stop");
385 pcm_play_lock();
387 if (pcm_playing)
389 logf(" pcm_play_dma_stop");
390 pcm_play_dma_stop();
391 pcm_play_stopped();
393 else
395 logf(" not playing");
398 pcm_play_unlock();
401 /**/
403 /* set frequency next frequency used by the audio hardware -
404 * what pcm_apply_settings will set */
405 void pcm_set_frequency(unsigned int samplerate)
407 logf("pcm_set_frequency");
409 int index;
411 #ifdef CONFIG_SAMPR_TYPES
412 unsigned int type = samplerate & SAMPR_TYPE_MASK;
413 samplerate &= ~SAMPR_TYPE_MASK;
415 /* For now, supported targets have direct conversion when configured with
416 * CONFIG_SAMPR_TYPES.
417 * Some hypothetical target with independent rates would need slightly
418 * different handling throughout this source. */
419 samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
420 #endif /* CONFIG_SAMPR_TYPES */
422 index = round_value_to_list32(samplerate, hw_freq_sampr,
423 HW_NUM_FREQ, false);
425 if (samplerate != hw_freq_sampr[index])
426 index = HW_FREQ_DEFAULT; /* Invalid = default */
428 pcm_sampr = hw_freq_sampr[index];
429 pcm_fsel = index;
432 /* apply pcm settings to the hardware */
433 void pcm_apply_settings(void)
435 logf("pcm_apply_settings");
437 pcm_wait_for_init();
439 if (pcm_sampr != pcm_curr_sampr)
441 logf(" pcm_dma_apply_settings");
442 pcm_dma_apply_settings();
443 pcm_curr_sampr = pcm_sampr;
447 #ifdef HAVE_RECORDING
448 /** Low level pcm recording apis **/
450 /* Next start for recording peaks */
451 static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR = NULL;
452 /* the registered callback function for when more data is available */
453 static volatile pcm_rec_callback_type
454 pcm_callback_more_ready SHAREDBSS_ATTR = NULL;
455 volatile pcm_status_callback_type
456 pcm_rec_status_callback SHAREDBSS_ATTR = NULL;
457 /* DMA transfer in is currently active */
458 volatile bool pcm_recording SHAREDBSS_ATTR = false;
460 /* Called internally by functions to reset the state */
461 static void pcm_recording_stopped(void)
463 pcm_recording = false;
464 pcm_callback_more_ready = NULL;
465 pcm_rec_status_callback = NULL;
469 * Return recording peaks - From the end of the last peak up to
470 * current write position.
472 void pcm_calculate_rec_peaks(int *left, int *right)
474 static uint16_t peaks[2];
476 if (pcm_recording)
478 const void *peak_addr = pcm_rec_peak_addr;
479 const void *addr = pcm_rec_dma_get_peak_buffer();
481 if (addr != NULL)
483 int count = (int)(((intptr_t)addr - (intptr_t)peak_addr) >> 2);
485 if (count > 0)
487 pcm_peak_peeker((int32_t *)peak_addr, count, peaks);
489 if (peak_addr == pcm_rec_peak_addr)
490 pcm_rec_peak_addr = addr;
493 /* else keep previous peak values */
495 else
497 peaks[0] = peaks[1] = 0;
500 if (left)
501 *left = peaks[0];
503 if (right)
504 *right = peaks[1];
505 } /* pcm_calculate_rec_peaks */
507 bool pcm_is_recording(void)
509 return pcm_recording;
512 /****************************************************************************
513 * Functions that do not require targeted implementation but only a targeted
514 * interface
517 void pcm_init_recording(void)
519 logf("pcm_init_recording");
521 pcm_wait_for_init();
523 /* Stop the beasty before attempting recording */
524 mixer_reset();
526 /* Recording init is locked unlike general pcm init since this is not
527 * just a one-time event at startup and it should and must be safe by
528 * now. */
529 pcm_rec_lock();
531 logf(" pcm_rec_dma_init");
532 pcm_recording_stopped();
533 pcm_rec_dma_init();
535 pcm_rec_unlock();
538 void pcm_close_recording(void)
540 logf("pcm_close_recording");
542 pcm_rec_lock();
544 if (pcm_recording)
546 logf(" pcm_rec_dma_stop");
547 pcm_rec_dma_stop();
548 pcm_recording_stopped();
551 logf(" pcm_rec_dma_close");
552 pcm_rec_dma_close();
554 pcm_rec_unlock();
557 void pcm_record_data(pcm_rec_callback_type more_ready,
558 pcm_status_callback_type status_cb,
559 void *addr, size_t size)
561 logf("pcm_record_data");
563 ALIGN_AUDIOBUF(addr, size);
565 if (!(addr && size))
567 logf(" no buffer");
568 return;
571 pcm_rec_lock();
573 pcm_callback_more_ready = more_ready;
574 pcm_rec_status_callback = status_cb;
576 /* Need a physical DMA address translation, if not already physical. */
577 pcm_rec_peak_addr = pcm_rec_dma_addr(addr);
579 logf(" pcm_rec_dma_start");
580 pcm_apply_settings();
581 pcm_rec_dma_start(addr, size);
582 pcm_recording = true;
584 pcm_rec_unlock();
585 } /* pcm_record_data */
587 void pcm_stop_recording(void)
589 logf("pcm_stop_recording");
591 pcm_rec_lock();
593 if (pcm_recording)
595 logf(" pcm_rec_dma_stop");
596 pcm_rec_dma_stop();
597 pcm_recording_stopped();
600 pcm_rec_unlock();
601 } /* pcm_stop_recording */
603 bool pcm_rec_dma_complete_callback(enum pcm_dma_status status,
604 void **addr, size_t *size)
606 /* Check status callback first if error */
607 if (status < PCM_DMAST_OK)
608 status = pcm_rec_dma_status_callback(status);
610 pcm_rec_callback_type have_more = pcm_callback_more_ready;
612 if (have_more && status >= PCM_DMAST_OK)
614 /* Call registered callback to obtain next buffer */
615 have_more(addr, size);
616 ALIGN_AUDIOBUF(*addr, *size);
618 if (*addr && *size)
620 /* Need a physical DMA address translation, if not already
621 * physical. */
622 pcm_rec_peak_addr = pcm_rec_dma_addr(*addr);
623 return true;
627 /* Error, callback missing or no more DMA to do */
628 pcm_rec_dma_stop();
629 pcm_recording_stopped();
631 return false;
634 #endif /* HAVE_RECORDING */