summaryrefslogtreecommitdiff
path: root/firmware/export
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-06-29 06:37:04 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-06-29 06:37:04 +0000
commita2b6703a369f6cdbfec1f150c408dadc877631fb (patch)
tree3145a8c1372c44711d38feefeba39c7d4098f139 /firmware/export
parent8411614b8a068a4f274c3841aa55aab1df1bc246 (diff)
downloadrockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.tar.gz
rockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.zip
Commit FS#12150 - Fully-functional audio mixer - and finally whip old limitations about playback of voice and other sounds when paused. Channels are independent in state and amplitude. Fade on stop/pause is handled by the channel's volume control rather than global volume which means it now works from anywhere. Opens up the possibility of plugin sounds during music playback by merely adding an additional channel enum. If any PCM drivers were not properly modified, see one of the last comments in the task for a description of the simple change that is expected. Some params are tunable in firmware/export/pcm-mixer.h as well.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30097 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/export')
-rw-r--r--firmware/export/config.h5
-rw-r--r--firmware/export/pcm-internal.h81
-rw-r--r--firmware/export/pcm.h44
-rw-r--r--firmware/export/pcm_mixer.h102
4 files changed, 190 insertions, 42 deletions
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 2c7c6e89db..70047ff866 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -1048,4 +1048,9 @@ Lyre prototype 1 */
1048#define HAVE_IO_PRIORITY 1048#define HAVE_IO_PRIORITY
1049#endif 1049#endif
1050 1050
1051#if defined(CPU_COLDIRE) || CONFIG_CPU == IMX31L
1052/* Can record and play simultaneously */
1053#define HAVE_PCM_FULL_DUPLEX
1054#endif
1055
1051#endif /* __CONFIG_H__ */ 1056#endif /* __CONFIG_H__ */
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
new file mode 100644
index 0000000000..d69138f534
--- /dev/null
+++ b/firmware/export/pcm-internal.h
@@ -0,0 +1,81 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Linus Nielsen Feltzing
11 * Copyright (C) 2011 by Michael Sevakis
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#ifndef PCM_INTERNAL_H
23#define PCM_INTERNAL_H
24
25/** The following are for internal use between pcm.c and target-
26 specific portion **/
27
28/* Called by the bottom layer ISR when more data is needed. Returns non-
29 * zero size if more data is to be played. Setting start to NULL
30 * forces stop. */
31void pcm_play_get_more_callback(void **start, size_t *size);
32
33/* Called by the bottom layer ISR after next transfer has begun in order
34 to fill more data for next "get more" callback to implement double-buffered
35 callbacks - except for a couple ASM handlers, help drivers to implement
36 this functionality with minimal overhead */
37static FORCE_INLINE void pcm_play_dma_started_callback(void)
38{
39 extern void (* pcm_play_dma_started)(void);
40 void (* callback)(void) = pcm_play_dma_started;
41 if (callback)
42 callback();
43}
44
45extern unsigned long pcm_curr_sampr;
46extern unsigned long pcm_sampr;
47extern int pcm_fsel;
48
49#ifdef HAVE_PCM_DMA_ADDRESS
50void * pcm_dma_addr(void *addr);
51#endif
52
53extern volatile bool pcm_playing;
54extern volatile bool pcm_paused;
55
56void pcm_play_dma_lock(void);
57void pcm_play_dma_unlock(void);
58void pcm_play_dma_init(void) INIT_ATTR;
59void pcm_play_dma_start(const void *addr, size_t size);
60void pcm_play_dma_stop(void);
61void pcm_play_dma_pause(bool pause);
62const void * pcm_play_dma_get_peak_buffer(int *count);
63
64void pcm_dma_apply_settings(void);
65
66#ifdef HAVE_RECORDING
67
68/* DMA transfer in is currently active */
69extern volatile bool pcm_recording;
70
71/* APIs implemented in the target-specific portion */
72void pcm_rec_dma_init(void);
73void pcm_rec_dma_close(void);
74void pcm_rec_dma_start(void *addr, size_t size);
75void pcm_rec_dma_record_more(void *start, size_t size);
76void pcm_rec_dma_stop(void);
77const void * pcm_rec_dma_get_peak_buffer(void);
78
79#endif /* HAVE_RECORDING */
80
81#endif /* PCM_INTERNAL_H */
diff --git a/firmware/export/pcm.h b/firmware/export/pcm.h
index 80b5b09a79..22c5ef350e 100644
--- a/firmware/export/pcm.h
+++ b/firmware/export/pcm.h
@@ -49,7 +49,7 @@
49 49
50/** RAW PCM routines used with playback and recording **/ 50/** RAW PCM routines used with playback and recording **/
51 51
52/* Typedef for registered callback */ 52/* Typedef for registered callbacks */
53typedef void (*pcm_play_callback_type)(unsigned char **start, 53typedef void (*pcm_play_callback_type)(unsigned char **start,
54 size_t *size); 54 size_t *size);
55typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); 55typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size);
@@ -90,34 +90,7 @@ void pcm_play_pause(bool play);
90bool pcm_is_paused(void); 90bool pcm_is_paused(void);
91bool pcm_is_playing(void); 91bool pcm_is_playing(void);
92 92
93/** The following are for internal use between pcm.c and target- 93void pcm_play_set_dma_started_callback(void (* callback)(void));
94 specific portion **/
95
96/* Called by the bottom layer ISR when more data is needed. Returns non-
97 * zero size if more data is to be played. Setting start to NULL
98 * forces stop. */
99void pcm_play_get_more_callback(void **start, size_t *size);
100
101extern unsigned long pcm_curr_sampr;
102extern unsigned long pcm_sampr;
103extern int pcm_fsel;
104
105#ifdef HAVE_PCM_DMA_ADDRESS
106void * pcm_dma_addr(void *addr);
107#endif
108
109extern volatile bool pcm_playing;
110extern volatile bool pcm_paused;
111
112void pcm_play_dma_lock(void);
113void pcm_play_dma_unlock(void);
114void pcm_play_dma_init(void) INIT_ATTR;
115void pcm_play_dma_start(const void *addr, size_t size);
116void pcm_play_dma_stop(void);
117void pcm_play_dma_pause(bool pause);
118const void * pcm_play_dma_get_peak_buffer(int *count);
119
120void pcm_dma_apply_settings(void);
121 94
122#ifdef HAVE_RECORDING 95#ifdef HAVE_RECORDING
123 96
@@ -148,19 +121,6 @@ void pcm_rec_more_ready_callback(int status, void **start, size_t *size);
148 121
149void pcm_calculate_rec_peaks(int *left, int *right); 122void pcm_calculate_rec_peaks(int *left, int *right);
150 123
151/** The following are for internal use between pcm.c and target-
152 specific portion **/
153/* DMA transfer in is currently active */
154extern volatile bool pcm_recording;
155
156/* APIs implemented in the target-specific portion */
157void pcm_rec_dma_init(void);
158void pcm_rec_dma_close(void);
159void pcm_rec_dma_start(void *addr, size_t size);
160void pcm_rec_dma_record_more(void *start, size_t size);
161void pcm_rec_dma_stop(void);
162const void * pcm_rec_dma_get_peak_buffer(void);
163
164#endif /* HAVE_RECORDING */ 124#endif /* HAVE_RECORDING */
165 125
166#endif /* PCM_PLAYBACK_H */ 126#endif /* PCM_PLAYBACK_H */
diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h
new file mode 100644
index 0000000000..3b420e1320
--- /dev/null
+++ b/firmware/export/pcm_mixer.h
@@ -0,0 +1,102 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef PCM_MIXER_H
23#define PCM_MIXER_H
24
25/** Simple config **/
26
27/* Length of PCM frames (always) */
28#if CONFIG_CPU == PP5002
29/* There's far less time to do mixing because HW FIFOs are short */
30#define MIX_FRAME_SAMPLES 64
31#else
32/* Assume HW DMA engine is available or sufficient latency exists in the
33 PCM pathway */
34#define MIX_FRAME_SAMPLES 256
35#endif
36
37#if defined(CPU_COLDFIRE) || defined(CPU_PP)
38/* For Coldfire, it's just faster
39 For PortalPlayer, this also avoids more expensive cache coherency */
40#define DOWNMIX_BUF_IBSS IBSS_ATTR
41#else
42/* Otherwise can't DMA from IRAM, IRAM is pointless or worse */
43#define DOWNMIX_BUF_IBSS
44#endif
45
46
47/** Definitions **/
48
49/* Channels are preassigned for simplicity */
50enum pcm_mixer_channel
51{
52 PCM_MIXER_CHAN_PLAYBACK = 0,
53 PCM_MIXER_CHAN_VOICE,
54#ifndef HAVE_HARDWARE_BEEP
55 PCM_MIXER_CHAN_BEEP,
56#endif
57 /* Add new channel indexes above this line */
58 PCM_MIXER_NUM_CHANNELS,
59};
60
61/* Channel playback states */
62enum channel_status
63{
64 CHANNEL_STOPPED = 0,
65 CHANNEL_PLAYING,
66 CHANNEL_PAUSED,
67};
68
69#define MIX_AMP_UNITY 0x00010000
70#define MIX_AMP_MUTE 0x00000000
71
72
73/** Public interfaces **/
74
75/* Start playback on a channel */
76void mixer_channel_play_data(enum pcm_mixer_channel channel,
77 pcm_play_callback_type get_more,
78 unsigned char *start, size_t size);
79
80/* Pause or resume a channel (when started) */
81void mixer_channel_play_pause(enum pcm_mixer_channel channel, bool play);
82
83/* Stop playback on a channel */
84void mixer_channel_stop(enum pcm_mixer_channel channel);
85
86/* Set channel's amplitude factor */
87void mixer_channel_set_amplitude(enum pcm_mixer_channel channel,
88 unsigned int amplitude);
89
90/* Return channel's playback status */
91enum channel_status mixer_channel_status(enum pcm_mixer_channel channel);
92
93/* Returns amount data remaining in channel before next callback */
94size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel);
95
96/* Return pointer to channel's playing audio data and the size remaining */
97void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
98
99/* Stop ALL channels and PCM and reset state */
100void mixer_reset(void);
101
102#endif /* PCM_MIXER_H */