diff options
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r-- | firmware/pcm_playback.c | 283 |
1 files changed, 0 insertions, 283 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c deleted file mode 100644 index d317b3708e..0000000000 --- a/firmware/pcm_playback.c +++ /dev/null | |||
@@ -1,283 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "system.h" | ||
20 | #include "kernel.h" | ||
21 | #include "logf.h" | ||
22 | #include "audio.h" | ||
23 | #include "sound.h" | ||
24 | |||
25 | /** | ||
26 | * APIs implemented in the target-specific portion: | ||
27 | * Public - | ||
28 | * pcm_init | ||
29 | * pcm_get_bytes_waiting | ||
30 | * pcm_calculate_peaks | ||
31 | * Semi-private - | ||
32 | * pcm_play_dma_start | ||
33 | * pcm_play_dma_stop | ||
34 | * pcm_play_pause_pause | ||
35 | * pcm_play_pause_unpause | ||
36 | */ | ||
37 | |||
38 | /** These items may be implemented target specifically or need to | ||
39 | be shared semi-privately **/ | ||
40 | |||
41 | /* the registered callback function to ask for more mp3 data */ | ||
42 | volatile pcm_more_callback_type pcm_callback_for_more = NULL; | ||
43 | volatile bool pcm_playing = false; | ||
44 | volatile bool pcm_paused = false; | ||
45 | |||
46 | void pcm_play_dma_start(const void *addr, size_t size); | ||
47 | void pcm_play_dma_stop(void); | ||
48 | void pcm_play_pause_pause(void); | ||
49 | void pcm_play_pause_unpause(void); | ||
50 | |||
51 | /** Functions that require targeted implementation **/ | ||
52 | |||
53 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == S3C2440) || (CONFIG_CPU == IMX31L) \ | ||
54 | || (CONFIG_CPU == DM320) | ||
55 | /* Implemented in target/... */ | ||
56 | #else | ||
57 | /* dummy functions for those not actually supporting all this yet */ | ||
58 | void pcm_apply_settings(void) | ||
59 | { | ||
60 | } | ||
61 | /** **/ | ||
62 | |||
63 | void pcm_mute(bool mute) | ||
64 | { | ||
65 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
66 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | ||
67 | audiohw_mute(mute); | ||
68 | #endif | ||
69 | if (mute) | ||
70 | sleep(HZ/16); | ||
71 | } | ||
72 | #endif /* defined(CPU_COLDFIRE) || (CONFIG_CPU == S3C2440) */ | ||
73 | |||
74 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == S3C2440) || defined(CPU_PP) \ | ||
75 | || (CONFIG_CPU == IMX31L) || (CONFIG_CPU == DM320) | ||
76 | /* Implemented in target/... */ | ||
77 | #else | ||
78 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | ||
79 | |||
80 | unsigned short* p IBSS_ATTR; | ||
81 | size_t p_size IBSS_ATTR; | ||
82 | |||
83 | void pcm_play_dma_start(const void *addr, size_t size) | ||
84 | { | ||
85 | p = (unsigned short*)addr; | ||
86 | p_size = size; | ||
87 | |||
88 | pcm_playing = true; | ||
89 | } | ||
90 | |||
91 | void pcm_play_dma_stop(void) | ||
92 | { | ||
93 | pcm_playing = false; | ||
94 | if (!audio_status()) | ||
95 | pcm_paused = false; | ||
96 | } | ||
97 | |||
98 | void pcm_play_pause_pause(void) | ||
99 | { | ||
100 | } | ||
101 | |||
102 | void pcm_play_pause_unpause(void) | ||
103 | { | ||
104 | } | ||
105 | |||
106 | void pcm_postinit(void) | ||
107 | { | ||
108 | audiohw_postinit(); | ||
109 | } | ||
110 | |||
111 | void pcm_set_frequency(unsigned int frequency) | ||
112 | { | ||
113 | (void)frequency; | ||
114 | pcm_freq = HW_SAMPR_DEFAULT; | ||
115 | } | ||
116 | size_t pcm_get_bytes_waiting(void) | ||
117 | { | ||
118 | return p_size; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * This function goes directly into the DMA buffer to calculate the left and | ||
123 | * right peak values. To avoid missing peaks it tries to look forward two full | ||
124 | * peek periods (2/HZ sec, 100% overlap), although it's always possible that | ||
125 | * the entire period will not be visible. To reduce CPU load it only looks at | ||
126 | * every third sample, and this can be reduced even further if needed (even | ||
127 | * every tenth sample would still be pretty accurate). | ||
128 | */ | ||
129 | |||
130 | /* Check for a peak every PEAK_STRIDE samples */ | ||
131 | #define PEAK_STRIDE 3 | ||
132 | /* Up to 1/50th of a second of audio for peak calculation */ | ||
133 | /* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ | ||
134 | #define PEAK_SAMPLES (44100/50) | ||
135 | void pcm_calculate_peaks(int *left, int *right) | ||
136 | { | ||
137 | short *addr; | ||
138 | short *end; | ||
139 | { | ||
140 | size_t samples = p_size / 4; | ||
141 | addr = p; | ||
142 | |||
143 | if (samples > PEAK_SAMPLES) | ||
144 | samples = PEAK_SAMPLES - (PEAK_STRIDE - 1); | ||
145 | else | ||
146 | samples -= MIN(PEAK_STRIDE - 1, samples); | ||
147 | |||
148 | end = &addr[samples * 2]; | ||
149 | } | ||
150 | |||
151 | if (left && right) { | ||
152 | int left_peak = 0, right_peak = 0; | ||
153 | |||
154 | while (addr < end) { | ||
155 | int value; | ||
156 | if ((value = addr [0]) > left_peak) | ||
157 | left_peak = value; | ||
158 | else if (-value > left_peak) | ||
159 | left_peak = -value; | ||
160 | |||
161 | if ((value = addr [PEAK_STRIDE | 1]) > right_peak) | ||
162 | right_peak = value; | ||
163 | else if (-value > right_peak) | ||
164 | right_peak = -value; | ||
165 | |||
166 | addr = &addr[PEAK_STRIDE * 2]; | ||
167 | } | ||
168 | |||
169 | *left = left_peak; | ||
170 | *right = right_peak; | ||
171 | } | ||
172 | else if (left || right) { | ||
173 | int peak_value = 0, value; | ||
174 | |||
175 | if (right) | ||
176 | addr += (PEAK_STRIDE | 1); | ||
177 | |||
178 | while (addr < end) { | ||
179 | if ((value = addr [0]) > peak_value) | ||
180 | peak_value = value; | ||
181 | else if (-value > peak_value) | ||
182 | peak_value = -value; | ||
183 | |||
184 | addr += PEAK_STRIDE * 2; | ||
185 | } | ||
186 | |||
187 | if (left) | ||
188 | *left = peak_value; | ||
189 | else | ||
190 | *right = peak_value; | ||
191 | } | ||
192 | } | ||
193 | #endif /* defined(CPU_COLDFIRE) || (CONFIG_CPU == S3C2440) || defined(CPU_PP) */ | ||
194 | |||
195 | /**************************************************************************** | ||
196 | * Functions that do not require targeted implementation but only a targeted | ||
197 | * interface | ||
198 | */ | ||
199 | |||
200 | /* Common code to pcm_play_data and pcm_play_pause | ||
201 | Returns true if DMA playback was started, else false. */ | ||
202 | bool pcm_play_data_start(pcm_more_callback_type get_more, | ||
203 | unsigned char *start, size_t size) | ||
204 | { | ||
205 | if (!(start && size)) | ||
206 | { | ||
207 | size = 0; | ||
208 | if (get_more) | ||
209 | get_more(&start, &size); | ||
210 | } | ||
211 | |||
212 | if (start && size) | ||
213 | { | ||
214 | pcm_play_dma_start(start, size); | ||
215 | return true; | ||
216 | } | ||
217 | |||
218 | return false; | ||
219 | } | ||
220 | |||
221 | void pcm_play_data(pcm_more_callback_type get_more, | ||
222 | unsigned char *start, size_t size) | ||
223 | { | ||
224 | pcm_callback_for_more = get_more; | ||
225 | |||
226 | if (pcm_play_data_start(get_more, start, size) && pcm_paused) | ||
227 | { | ||
228 | pcm_paused = false; | ||
229 | pcm_play_pause(false); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | void pcm_play_pause(bool play) | ||
234 | { | ||
235 | bool needs_change = pcm_paused == play; | ||
236 | |||
237 | /* This needs to be done ahead of the rest to prevent infinite | ||
238 | recursion from pcm_play_data */ | ||
239 | pcm_paused = !play; | ||
240 | |||
241 | if (pcm_playing && needs_change) | ||
242 | { | ||
243 | if (play) | ||
244 | { | ||
245 | if (pcm_get_bytes_waiting()) | ||
246 | { | ||
247 | logf("unpause"); | ||
248 | pcm_play_pause_unpause(); | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | logf("unpause, no data waiting"); | ||
253 | if (!pcm_play_data_start(pcm_callback_for_more, NULL, 0)) | ||
254 | { | ||
255 | pcm_play_dma_stop(); | ||
256 | logf("unpause attempted, no data"); | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | logf("pause"); | ||
263 | pcm_play_pause_pause(); | ||
264 | } | ||
265 | } /* pcm_playing && needs_change */ | ||
266 | } | ||
267 | |||
268 | void pcm_play_stop(void) | ||
269 | { | ||
270 | if (pcm_playing) | ||
271 | pcm_play_dma_stop(); | ||
272 | } | ||
273 | |||
274 | bool pcm_is_playing(void) | ||
275 | { | ||
276 | return pcm_playing; | ||
277 | } | ||
278 | |||
279 | bool pcm_is_paused(void) | ||
280 | { | ||
281 | return pcm_paused; | ||
282 | } | ||
283 | |||