Introduce names for header and row color in the tables so that they are the same...
[kugel-rb.git] / uisimulator / sdl / sound.c
blob428983a1b89ebe3408768e6602ab95eb0ba880a6
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);
99 if (udata.debug != NULL) {
100 fclose(udata.debug);
101 udata.debug = NULL;
102 DEBUGF("Audio debug file closed\n");
106 void pcm_play_dma_pause(bool pause)
108 if (pause)
109 SDL_PauseAudio(1);
110 else
111 SDL_PauseAudio(0);
114 size_t pcm_get_bytes_waiting(void)
116 return pcm_data_size;
119 extern int sim_volume; /* in firmware/sound.c */
120 void write_to_soundcard(struct pcm_udata *udata) {
121 if (debug_audio && (udata->debug == NULL)) {
122 udata->debug = fopen("audiodebug.raw", "ab");
123 DEBUGF("Audio debug file open\n");
126 if (cvt.needed) {
127 Uint32 rd = udata->num_in;
128 Uint32 wr = (double)rd * cvt.len_ratio;
130 if (wr > udata->num_out) {
131 wr = udata->num_out;
132 rd = (double)wr / cvt.len_ratio;
134 if (rd > udata->num_in)
136 rd = udata->num_in;
137 wr = (double)rd * cvt.len_ratio;
141 if (wr == 0 || rd == 0)
143 udata->num_out = udata->num_in = 0;
144 return;
147 if (cvt_status > 0) {
148 cvt.len = rd * pcm_sample_bytes;
149 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
151 memcpy(cvt.buf, pcm_data, cvt.len);
153 SDL_ConvertAudio(&cvt);
154 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
156 udata->num_in = cvt.len / pcm_sample_bytes;
157 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
159 if (udata->debug != NULL) {
160 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
163 free(cvt.buf);
165 else {
166 /* Convert is bad, so do silence */
167 Uint32 num = wr*obtained.channels;
168 udata->num_in = rd;
169 udata->num_out = wr;
171 switch (pcm_channel_bytes)
173 case 1:
175 Uint8 *stream = udata->stream;
176 while (num-- > 0)
177 *stream++ = obtained.silence;
178 break;
180 case 2:
182 Uint16 *stream = (Uint16 *)udata->stream;
183 while (num-- > 0)
184 *stream++ = obtained.silence;
185 break;
189 if (udata->debug != NULL) {
190 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
193 } else {
194 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
195 SDL_MixAudio(udata->stream, pcm_data,
196 udata->num_out * pcm_sample_bytes, sim_volume);
198 if (udata->debug != NULL) {
199 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
200 udata->debug);
205 void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
207 udata->stream = stream;
209 /* Write what we have in the PCM buffer */
210 if (pcm_data_size > 0)
211 goto start;
213 /* Audio card wants more? Get some more then. */
214 while (len > 0) {
215 if ((ssize_t)pcm_data_size <= 0) {
216 pcm_data_size = 0;
218 if (pcm_callback_for_more)
219 pcm_callback_for_more(&pcm_data, &pcm_data_size);
222 if (pcm_data_size > 0) {
223 start:
224 udata->num_in = pcm_data_size / pcm_sample_bytes;
225 udata->num_out = len / pcm_sample_bytes;
227 write_to_soundcard(udata);
229 udata->num_in *= pcm_sample_bytes;
230 udata->num_out *= pcm_sample_bytes;
232 pcm_data += udata->num_in;
233 pcm_data_size -= udata->num_in;
234 udata->stream += udata->num_out;
235 len -= udata->num_out;
236 } else {
237 DEBUGF("sdl_audio_callback: No Data.\n");
238 pcm_play_dma_stop();
239 pcm_play_dma_stopped_callback();
240 break;
245 const void * pcm_play_dma_get_peak_buffer(int *count)
247 uintptr_t addr = (uintptr_t)pcm_data;
248 *count = pcm_data_size / 4;
249 return (void *)((addr + 2) & ~3);
252 #ifdef HAVE_RECORDING
253 void pcm_rec_lock(void)
257 void pcm_rec_unlock(void)
261 void pcm_rec_dma_init(void)
265 void pcm_rec_dma_close(void)
269 void pcm_rec_dma_start(void *start, size_t size)
271 (void)start;
272 (void)size;
275 void pcm_rec_dma_stop(void)
279 void pcm_record_more(void *start, size_t size)
281 (void)start;
282 (void)size;
285 unsigned long pcm_rec_status(void)
287 return 0;
290 const void * pcm_rec_dma_get_peak_buffer(int *count)
292 *count = 0;
293 return NULL;
296 #endif /* HAVE_RECORDING */
298 void pcm_play_dma_init(void)
300 SDL_AudioSpec wanted_spec;
301 udata.debug = NULL;
303 if (debug_audio) {
304 udata.debug = fopen("audiodebug.raw", "wb");
305 DEBUGF("Audio debug file open\n");
308 /* Set 16-bit stereo audio at 44Khz */
309 wanted_spec.freq = 44100;
310 wanted_spec.format = AUDIO_S16SYS;
311 wanted_spec.channels = 2;
312 wanted_spec.samples = 2048;
313 wanted_spec.callback =
314 (void (SDLCALL *)(void *userdata,
315 Uint8 *stream, int len))sdl_audio_callback;
316 wanted_spec.userdata = &udata;
318 /* Open the audio device and start playing sound! */
319 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
320 fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
321 return;
324 switch (obtained.format)
326 case AUDIO_U8:
327 case AUDIO_S8:
328 pcm_channel_bytes = 1;
329 break;
330 case AUDIO_U16LSB:
331 case AUDIO_S16LSB:
332 case AUDIO_U16MSB:
333 case AUDIO_S16MSB:
334 pcm_channel_bytes = 2;
335 break;
336 default:
337 fprintf(stderr, "Unknown sample format obtained: %u\n",
338 (unsigned)obtained.format);
339 return;
342 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
344 pcm_dma_apply_settings_nolock();
347 void pcm_postinit(void)