summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/sdl/pcm-sdl.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-05-15 21:02:47 +0000
committerThomas Martitz <kugel@rockbox.org>2010-05-15 21:02:47 +0000
commit3d0cee8abbaf764958743e8a7851eee94e60a913 (patch)
treea96b1ec825003a71643a7da4707c300f64824f82 /firmware/target/hosted/sdl/pcm-sdl.c
parentdcf442e61f21fb2aef5ce7de0547f733557b156e (diff)
downloadrockbox-3d0cee8abbaf764958743e8a7851eee94e60a913.tar.gz
rockbox-3d0cee8abbaf764958743e8a7851eee94e60a913.zip
- Move uisimulator/sdl/*.[ch] into the target tree, under firmware/target/hosted/sdl, uisdl.c is split up across button-sdl.c and system-sdl.c.
- Refactor the program startup. main() is now in main.c like on target, and the implicit application thread will now act as our main thread (previously a separate one was created for this in thread initialization). This is part of Rockbox as an application and is the first step to make an application port from the uisimulator. In a further step the sim bits from the sdl build will be separated out. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26065 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/hosted/sdl/pcm-sdl.c')
-rw-r--r--firmware/target/hosted/sdl/pcm-sdl.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c
new file mode 100644
index 0000000000..1772db94f4
--- /dev/null
+++ b/firmware/target/hosted/sdl/pcm-sdl.c
@@ -0,0 +1,373 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Nick Lanham
11 * Copyright (C) 2010 by Thomas Martitz
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
23#include "autoconf.h"
24
25#include <stdlib.h>
26#include <stdbool.h>
27#include <SDL.h>
28#include "config.h"
29#include "debug.h"
30#include "sound.h"
31#include "audiohw.h"
32#include "system.h"
33
34#include "pcm.h"
35#include "pcm_sampr.h"
36
37#ifdef DEBUG
38#include <stdio.h>
39extern bool debug_audio;
40#endif
41
42static int sim_volume = 0;
43
44#if CONFIG_CODEC == SWCODEC
45static int cvt_status = -1;
46
47static Uint8* pcm_data;
48static size_t pcm_data_size;
49static size_t pcm_sample_bytes;
50static size_t pcm_channel_bytes;
51
52struct pcm_udata
53{
54 Uint8 *stream;
55 Uint32 num_in;
56 Uint32 num_out;
57#ifdef DEBUG
58 FILE *debug;
59#endif
60} udata;
61
62static SDL_AudioSpec obtained;
63static SDL_AudioCVT cvt;
64
65void pcm_play_lock(void)
66{
67 SDL_LockAudio();
68}
69
70void pcm_play_unlock(void)
71{
72 SDL_UnlockAudio();
73}
74
75static void pcm_dma_apply_settings_nolock(void)
76{
77 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
78 obtained.format, obtained.channels, obtained.freq);
79
80 if (cvt_status < 0) {
81 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
82 }
83}
84
85void pcm_dma_apply_settings(void)
86{
87 pcm_play_lock();
88 pcm_dma_apply_settings_nolock();
89 pcm_play_unlock();
90}
91
92void pcm_play_dma_start(const void *addr, size_t size)
93{
94 pcm_dma_apply_settings_nolock();
95
96 pcm_data = (Uint8 *) addr;
97 pcm_data_size = size;
98
99 SDL_PauseAudio(0);
100}
101
102void pcm_play_dma_stop(void)
103{
104 SDL_PauseAudio(1);
105#ifdef DEBUG
106 if (udata.debug != NULL) {
107 fclose(udata.debug);
108 udata.debug = NULL;
109 DEBUGF("Audio debug file closed\n");
110 }
111#endif
112}
113
114void pcm_play_dma_pause(bool pause)
115{
116 if (pause)
117 SDL_PauseAudio(1);
118 else
119 SDL_PauseAudio(0);
120}
121
122size_t pcm_get_bytes_waiting(void)
123{
124 return pcm_data_size;
125}
126
127void write_to_soundcard(struct pcm_udata *udata)
128{
129#ifdef DEBUG
130 if (debug_audio && (udata->debug == NULL)) {
131 udata->debug = fopen("audiodebug.raw", "ab");
132 DEBUGF("Audio debug file open\n");
133 }
134#endif
135 if (cvt.needed) {
136 Uint32 rd = udata->num_in;
137 Uint32 wr = (double)rd * cvt.len_ratio;
138
139 if (wr > udata->num_out) {
140 wr = udata->num_out;
141 rd = (double)wr / cvt.len_ratio;
142
143 if (rd > udata->num_in)
144 {
145 rd = udata->num_in;
146 wr = (double)rd * cvt.len_ratio;
147 }
148 }
149
150 if (wr == 0 || rd == 0)
151 {
152 udata->num_out = udata->num_in = 0;
153 return;
154 }
155
156 if (cvt_status > 0) {
157 cvt.len = rd * pcm_sample_bytes;
158 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
159
160 memcpy(cvt.buf, pcm_data, cvt.len);
161
162 SDL_ConvertAudio(&cvt);
163 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
164
165 udata->num_in = cvt.len / pcm_sample_bytes;
166 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
167
168#ifdef DEBUG
169 if (udata->debug != NULL) {
170 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
171 }
172#endif
173 free(cvt.buf);
174 }
175 else {
176 /* Convert is bad, so do silence */
177 Uint32 num = wr*obtained.channels;
178 udata->num_in = rd;
179 udata->num_out = wr;
180
181 switch (pcm_channel_bytes)
182 {
183 case 1:
184 {
185 Uint8 *stream = udata->stream;
186 while (num-- > 0)
187 *stream++ = obtained.silence;
188 break;
189 }
190 case 2:
191 {
192 Uint16 *stream = (Uint16 *)udata->stream;
193 while (num-- > 0)
194 *stream++ = obtained.silence;
195 break;
196 }
197 }
198#ifdef DEBUG
199 if (udata->debug != NULL) {
200 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
201 }
202#endif
203 }
204 } else {
205 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
206 SDL_MixAudio(udata->stream, pcm_data,
207 udata->num_out * pcm_sample_bytes, sim_volume);
208#ifdef DEBUG
209 if (udata->debug != NULL) {
210 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
211 udata->debug);
212 }
213#endif
214 }
215}
216
217void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
218{
219 udata->stream = stream;
220
221 /* Write what we have in the PCM buffer */
222 if (pcm_data_size > 0)
223 goto start;
224
225 /* Audio card wants more? Get some more then. */
226 while (len > 0) {
227 if ((ssize_t)pcm_data_size <= 0) {
228 pcm_data_size = 0;
229
230 if (pcm_callback_for_more)
231 pcm_callback_for_more(&pcm_data, &pcm_data_size);
232 }
233
234 if (pcm_data_size > 0) {
235 start:
236 udata->num_in = pcm_data_size / pcm_sample_bytes;
237 udata->num_out = len / pcm_sample_bytes;
238
239 write_to_soundcard(udata);
240
241 udata->num_in *= pcm_sample_bytes;
242 udata->num_out *= pcm_sample_bytes;
243
244 pcm_data += udata->num_in;
245 pcm_data_size -= udata->num_in;
246 udata->stream += udata->num_out;
247 len -= udata->num_out;
248 } else {
249 DEBUGF("sdl_audio_callback: No Data.\n");
250 pcm_play_dma_stop();
251 pcm_play_dma_stopped_callback();
252 break;
253 }
254 }
255}
256
257const void * pcm_play_dma_get_peak_buffer(int *count)
258{
259 uintptr_t addr = (uintptr_t)pcm_data;
260 *count = pcm_data_size / 4;
261 return (void *)((addr + 2) & ~3);
262}
263
264#ifdef HAVE_RECORDING
265void pcm_rec_lock(void)
266{
267}
268
269void pcm_rec_unlock(void)
270{
271}
272
273void pcm_rec_dma_init(void)
274{
275}
276
277void pcm_rec_dma_close(void)
278{
279}
280
281void pcm_rec_dma_start(void *start, size_t size)
282{
283 (void)start;
284 (void)size;
285}
286
287void pcm_rec_dma_stop(void)
288{
289}
290
291void pcm_rec_dma_record_more(void *start, size_t size)
292{
293 (void)start;
294 (void)size;
295}
296
297unsigned long pcm_rec_status(void)
298{
299 return 0;
300}
301
302const void * pcm_rec_dma_get_peak_buffer(void)
303{
304 return NULL;
305}
306
307#endif /* HAVE_RECORDING */
308
309void pcm_play_dma_init(void)
310{
311 if (SDL_InitSubSystem(SDL_INIT_AUDIO))
312 {
313 DEBUGF("Could not initialize SDL audio subsystem!\n");
314 return;
315 }
316
317 SDL_AudioSpec wanted_spec;
318#ifdef DEBUG
319 udata.debug = NULL;
320 if (debug_audio) {
321 udata.debug = fopen("audiodebug.raw", "wb");
322 DEBUGF("Audio debug file open\n");
323 }
324#endif
325 /* Set 16-bit stereo audio at 44Khz */
326 wanted_spec.freq = 44100;
327 wanted_spec.format = AUDIO_S16SYS;
328 wanted_spec.channels = 2;
329 wanted_spec.samples = 2048;
330 wanted_spec.callback =
331 (void (SDLCALL *)(void *userdata,
332 Uint8 *stream, int len))sdl_audio_callback;
333 wanted_spec.userdata = &udata;
334
335 /* Open the audio device and start playing sound! */
336 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
337 DEBUGF("Unable to open audio: %s\n", SDL_GetError());
338 return;
339 }
340
341 switch (obtained.format)
342 {
343 case AUDIO_U8:
344 case AUDIO_S8:
345 pcm_channel_bytes = 1;
346 break;
347 case AUDIO_U16LSB:
348 case AUDIO_S16LSB:
349 case AUDIO_U16MSB:
350 case AUDIO_S16MSB:
351 pcm_channel_bytes = 2;
352 break;
353 default:
354 DEBUGF("Unknown sample format obtained: %u\n",
355 (unsigned)obtained.format);
356 return;
357 }
358
359 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
360
361 pcm_dma_apply_settings_nolock();
362}
363
364void pcm_postinit(void)
365{
366}
367
368void pcm_set_mixer_volume(int volume)
369{
370 sim_volume = volume;
371}
372
373#endif /* CONFIG_CODEC == SWCODEC */