Cleaner solution to plugin-included core files.
[kugel-rb.git] / uisimulator / sdl / sound.c
blob39abc85aca6ab80f977c77d327edca165a625979
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Nick Lanham
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "autoconf.h"
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <memory.h>
27 #include "debug.h"
28 #include "kernel.h"
29 #include "sound.h"
31 #include "pcm.h"
32 #include "pcm_sampr.h"
33 #include "SDL.h"
35 static int cvt_status = -1;
37 static Uint8* pcm_data;
38 static size_t pcm_data_size;
39 static size_t pcm_sample_bytes;
40 static size_t pcm_channel_bytes;
42 struct pcm_udata
44 Uint8 *stream;
45 Uint32 num_in;
46 Uint32 num_out;
47 FILE *debug;
48 } udata;
50 static SDL_AudioSpec obtained;
51 static SDL_AudioCVT cvt;
53 extern bool debug_audio;
55 #ifndef MIN
56 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
57 #endif
59 void pcm_play_lock(void)
61 SDL_LockAudio();
64 void pcm_play_unlock(void)
66 SDL_UnlockAudio();
69 static void pcm_dma_apply_settings_nolock(void)
71 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
72 obtained.format, obtained.channels, obtained.freq);
74 if (cvt_status < 0) {
75 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
79 void pcm_dma_apply_settings(void)
81 pcm_play_lock();
82 pcm_dma_apply_settings_nolock();
83 pcm_play_unlock();
86 void pcm_play_dma_start(const void *addr, size_t size)
88 pcm_dma_apply_settings_nolock();
90 pcm_data = (Uint8 *) addr;
91 pcm_data_size = size;
93 SDL_PauseAudio(0);
96 void pcm_play_dma_stop(void)
98 SDL_PauseAudio(1);
101 void pcm_play_dma_pause(bool pause)
103 if (pause)
104 SDL_PauseAudio(1);
105 else
106 SDL_PauseAudio(0);
109 size_t pcm_get_bytes_waiting(void)
111 return pcm_data_size;
114 extern int sim_volume; /* in firmware/sound.c */
115 void write_to_soundcard(struct pcm_udata *udata) {
116 if (cvt.needed) {
117 Uint32 rd = udata->num_in;
118 Uint32 wr = (double)rd * cvt.len_ratio;
120 if (wr > udata->num_out) {
121 wr = udata->num_out;
122 rd = (double)wr / cvt.len_ratio;
124 if (rd > udata->num_in)
126 rd = udata->num_in;
127 wr = (double)rd * cvt.len_ratio;
131 if (wr == 0 || rd == 0)
133 udata->num_out = udata->num_in = 0;
134 return;
137 if (cvt_status > 0) {
138 cvt.len = rd * pcm_sample_bytes;
139 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
141 memcpy(cvt.buf, pcm_data, cvt.len);
143 SDL_ConvertAudio(&cvt);
144 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
146 udata->num_in = cvt.len / pcm_sample_bytes;
147 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
149 if (udata->debug != NULL) {
150 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
153 free(cvt.buf);
155 else {
156 /* Convert is bad, so do silence */
157 Uint32 num = wr*obtained.channels;
158 udata->num_in = rd;
159 udata->num_out = wr;
161 switch (pcm_channel_bytes)
163 case 1:
165 Uint8 *stream = udata->stream;
166 while (num-- > 0)
167 *stream++ = obtained.silence;
168 break;
170 case 2:
172 Uint16 *stream = (Uint16 *)udata->stream;
173 while (num-- > 0)
174 *stream++ = obtained.silence;
175 break;
179 if (udata->debug != NULL) {
180 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
183 } else {
184 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
185 SDL_MixAudio(udata->stream, pcm_data,
186 udata->num_out * pcm_sample_bytes, sim_volume);
188 if (udata->debug != NULL) {
189 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
190 udata->debug);
195 void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
197 udata->stream = stream;
199 /* Write what we have in the PCM buffer */
200 if (pcm_data_size > 0)
201 goto start;
203 /* Audio card wants more? Get some more then. */
204 while (len > 0) {
205 if ((ssize_t)pcm_data_size <= 0) {
206 pcm_data_size = 0;
208 if (pcm_callback_for_more)
209 pcm_callback_for_more(&pcm_data, &pcm_data_size);
212 if (pcm_data_size > 0) {
213 start:
214 udata->num_in = pcm_data_size / pcm_sample_bytes;
215 udata->num_out = len / pcm_sample_bytes;
217 write_to_soundcard(udata);
219 udata->num_in *= pcm_sample_bytes;
220 udata->num_out *= pcm_sample_bytes;
222 pcm_data += udata->num_in;
223 pcm_data_size -= udata->num_in;
224 udata->stream += udata->num_out;
225 len -= udata->num_out;
226 } else {
227 DEBUGF("sdl_audio_callback: No Data.\n");
228 pcm_play_dma_stop();
229 pcm_play_dma_stopped_callback();
230 break;
235 const void * pcm_play_dma_get_peak_buffer(int *count)
237 uintptr_t addr = (uintptr_t)pcm_data;
238 *count = pcm_data_size / 4;
239 return (void *)((addr + 2) & ~3);
242 #ifdef HAVE_RECORDING
243 void pcm_rec_lock(void)
247 void pcm_rec_unlock(void)
251 void pcm_rec_dma_init(void)
255 void pcm_rec_dma_close(void)
259 void pcm_rec_dma_start(void *start, size_t size)
261 (void)start;
262 (void)size;
265 void pcm_rec_dma_stop(void)
269 void pcm_record_more(void *start, size_t size)
271 (void)start;
272 (void)size;
275 unsigned long pcm_rec_status(void)
277 return 0;
280 const void * pcm_rec_dma_get_peak_buffer(int *count)
282 *count = 0;
283 return NULL;
286 #endif /* HAVE_RECORDING */
288 void pcm_play_dma_init(void)
290 SDL_AudioSpec wanted_spec;
291 udata.debug = NULL;
293 if (debug_audio) {
294 udata.debug = fopen("audiodebug.raw", "wb");
297 /* Set 16-bit stereo audio at 44Khz */
298 wanted_spec.freq = 44100;
299 wanted_spec.format = AUDIO_S16SYS;
300 wanted_spec.channels = 2;
301 wanted_spec.samples = 2048;
302 wanted_spec.callback =
303 (void (SDLCALL *)(void *userdata,
304 Uint8 *stream, int len))sdl_audio_callback;
305 wanted_spec.userdata = &udata;
307 /* Open the audio device and start playing sound! */
308 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
309 fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
310 return;
313 switch (obtained.format)
315 case AUDIO_U8:
316 case AUDIO_S8:
317 pcm_channel_bytes = 1;
318 break;
319 case AUDIO_U16LSB:
320 case AUDIO_S16LSB:
321 case AUDIO_U16MSB:
322 case AUDIO_S16MSB:
323 pcm_channel_bytes = 2;
324 break;
325 default:
326 fprintf(stderr, "Unknown sample format obtained: %u\n",
327 (unsigned)obtained.format);
328 return;
331 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
333 pcm_dma_apply_settings_nolock();
336 void pcm_postinit(void)