summaryrefslogtreecommitdiff
path: root/firmware/pcm_playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r--firmware/pcm_playback.c283
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 */
42volatile pcm_more_callback_type pcm_callback_for_more = NULL;
43volatile bool pcm_playing = false;
44volatile bool pcm_paused = false;
45
46void pcm_play_dma_start(const void *addr, size_t size);
47void pcm_play_dma_stop(void);
48void pcm_play_pause_pause(void);
49void 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 */
58void pcm_apply_settings(void)
59{
60}
61/** **/
62
63void 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
78static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
79
80unsigned short* p IBSS_ATTR;
81size_t p_size IBSS_ATTR;
82
83void 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
91void pcm_play_dma_stop(void)
92{
93 pcm_playing = false;
94 if (!audio_status())
95 pcm_paused = false;
96}
97
98void pcm_play_pause_pause(void)
99{
100}
101
102void pcm_play_pause_unpause(void)
103{
104}
105
106void pcm_postinit(void)
107{
108 audiohw_postinit();
109}
110
111void pcm_set_frequency(unsigned int frequency)
112{
113 (void)frequency;
114 pcm_freq = HW_SAMPR_DEFAULT;
115}
116size_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)
135void 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. */
202bool 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
221void 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
233void 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
268void pcm_play_stop(void)
269{
270 if (pcm_playing)
271 pcm_play_dma_stop();
272}
273
274bool pcm_is_playing(void)
275{
276 return pcm_playing;
277}
278
279bool pcm_is_paused(void)
280{
281 return pcm_paused;
282}
283