diff options
Diffstat (limited to 'firmware/export')
-rw-r--r-- | firmware/export/config.h | 5 | ||||
-rw-r--r-- | firmware/export/pcm-internal.h | 81 | ||||
-rw-r--r-- | firmware/export/pcm.h | 44 | ||||
-rw-r--r-- | firmware/export/pcm_mixer.h | 102 |
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. */ | ||
31 | void 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 */ | ||
37 | static 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 | |||
45 | extern unsigned long pcm_curr_sampr; | ||
46 | extern unsigned long pcm_sampr; | ||
47 | extern int pcm_fsel; | ||
48 | |||
49 | #ifdef HAVE_PCM_DMA_ADDRESS | ||
50 | void * pcm_dma_addr(void *addr); | ||
51 | #endif | ||
52 | |||
53 | extern volatile bool pcm_playing; | ||
54 | extern volatile bool pcm_paused; | ||
55 | |||
56 | void pcm_play_dma_lock(void); | ||
57 | void pcm_play_dma_unlock(void); | ||
58 | void pcm_play_dma_init(void) INIT_ATTR; | ||
59 | void pcm_play_dma_start(const void *addr, size_t size); | ||
60 | void pcm_play_dma_stop(void); | ||
61 | void pcm_play_dma_pause(bool pause); | ||
62 | const void * pcm_play_dma_get_peak_buffer(int *count); | ||
63 | |||
64 | void pcm_dma_apply_settings(void); | ||
65 | |||
66 | #ifdef HAVE_RECORDING | ||
67 | |||
68 | /* DMA transfer in is currently active */ | ||
69 | extern volatile bool pcm_recording; | ||
70 | |||
71 | /* APIs implemented in the target-specific portion */ | ||
72 | void pcm_rec_dma_init(void); | ||
73 | void pcm_rec_dma_close(void); | ||
74 | void pcm_rec_dma_start(void *addr, size_t size); | ||
75 | void pcm_rec_dma_record_more(void *start, size_t size); | ||
76 | void pcm_rec_dma_stop(void); | ||
77 | const 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 */ |
53 | typedef void (*pcm_play_callback_type)(unsigned char **start, | 53 | typedef void (*pcm_play_callback_type)(unsigned char **start, |
54 | size_t *size); | 54 | size_t *size); |
55 | typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); | 55 | typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); |
@@ -90,34 +90,7 @@ void pcm_play_pause(bool play); | |||
90 | bool pcm_is_paused(void); | 90 | bool pcm_is_paused(void); |
91 | bool pcm_is_playing(void); | 91 | bool pcm_is_playing(void); |
92 | 92 | ||
93 | /** The following are for internal use between pcm.c and target- | 93 | void 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. */ | ||
99 | void pcm_play_get_more_callback(void **start, size_t *size); | ||
100 | |||
101 | extern unsigned long pcm_curr_sampr; | ||
102 | extern unsigned long pcm_sampr; | ||
103 | extern int pcm_fsel; | ||
104 | |||
105 | #ifdef HAVE_PCM_DMA_ADDRESS | ||
106 | void * pcm_dma_addr(void *addr); | ||
107 | #endif | ||
108 | |||
109 | extern volatile bool pcm_playing; | ||
110 | extern volatile bool pcm_paused; | ||
111 | |||
112 | void pcm_play_dma_lock(void); | ||
113 | void pcm_play_dma_unlock(void); | ||
114 | void pcm_play_dma_init(void) INIT_ATTR; | ||
115 | void pcm_play_dma_start(const void *addr, size_t size); | ||
116 | void pcm_play_dma_stop(void); | ||
117 | void pcm_play_dma_pause(bool pause); | ||
118 | const void * pcm_play_dma_get_peak_buffer(int *count); | ||
119 | |||
120 | void 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 | ||
149 | void pcm_calculate_rec_peaks(int *left, int *right); | 122 | void 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 */ | ||
154 | extern volatile bool pcm_recording; | ||
155 | |||
156 | /* APIs implemented in the target-specific portion */ | ||
157 | void pcm_rec_dma_init(void); | ||
158 | void pcm_rec_dma_close(void); | ||
159 | void pcm_rec_dma_start(void *addr, size_t size); | ||
160 | void pcm_rec_dma_record_more(void *start, size_t size); | ||
161 | void pcm_rec_dma_stop(void); | ||
162 | const 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 */ | ||
50 | enum 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 */ | ||
62 | enum 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 */ | ||
76 | void 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) */ | ||
81 | void mixer_channel_play_pause(enum pcm_mixer_channel channel, bool play); | ||
82 | |||
83 | /* Stop playback on a channel */ | ||
84 | void mixer_channel_stop(enum pcm_mixer_channel channel); | ||
85 | |||
86 | /* Set channel's amplitude factor */ | ||
87 | void mixer_channel_set_amplitude(enum pcm_mixer_channel channel, | ||
88 | unsigned int amplitude); | ||
89 | |||
90 | /* Return channel's playback status */ | ||
91 | enum channel_status mixer_channel_status(enum pcm_mixer_channel channel); | ||
92 | |||
93 | /* Returns amount data remaining in channel before next callback */ | ||
94 | size_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 */ | ||
97 | void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); | ||
98 | |||
99 | /* Stop ALL channels and PCM and reset state */ | ||
100 | void mixer_reset(void); | ||
101 | |||
102 | #endif /* PCM_MIXER_H */ | ||