only send a Charging Only interface if nothing else is sent
[kugel-rb.git] / uisimulator / sdl / sound.c
blob169ff1c85638f0c6e48c0ba72b9c2bf969f0fd16
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Nick Lanham
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "autoconf.h"
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <memory.h>
25 #include "debug.h"
26 #include "kernel.h"
27 #include "sound.h"
29 #include "pcm.h"
30 #include "pcm_sampr.h"
31 #include "SDL.h"
33 static int cvt_status = -1;
34 static unsigned long pcm_frequency = SAMPR_44;
36 static Uint8* pcm_data;
37 static size_t pcm_data_size;
38 static size_t pcm_sample_bytes;
39 static size_t pcm_channel_bytes;
41 struct pcm_udata
43 Uint8 *stream;
44 Uint32 num_in;
45 Uint32 num_out;
46 FILE *debug;
47 } udata;
49 static SDL_AudioSpec obtained;
50 static SDL_AudioCVT cvt;
52 extern bool debug_audio;
54 #ifndef MIN
55 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
56 #endif
58 void pcm_play_lock(void)
60 SDL_LockAudio();
63 void pcm_play_unlock(void)
65 SDL_UnlockAudio();
68 static void pcm_apply_settings_nolock(void)
70 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_frequency,
71 obtained.format, obtained.channels, obtained.freq);
73 pcm_curr_sampr = pcm_frequency;
75 if (cvt_status < 0) {
76 cvt.len_ratio = (double)obtained.freq / (double)pcm_curr_sampr;
80 void pcm_apply_settings(void)
82 pcm_play_lock();
83 pcm_apply_settings_nolock();
84 pcm_play_unlock();
87 void pcm_play_dma_start(const void *addr, size_t size)
89 pcm_apply_settings_nolock();
91 pcm_data = (Uint8 *) addr;
92 pcm_data_size = size;
94 SDL_PauseAudio(0);
97 void pcm_play_dma_stop(void)
99 SDL_PauseAudio(1);
102 void pcm_play_dma_pause(bool pause)
104 if (pause)
105 SDL_PauseAudio(1);
106 else
107 SDL_PauseAudio(0);
110 size_t pcm_get_bytes_waiting(void)
112 return pcm_data_size;
115 void pcm_set_frequency(unsigned int frequency)
117 switch (frequency)
119 HW_HAVE_8_( case SAMPR_8:)
120 HW_HAVE_11_(case SAMPR_11:)
121 HW_HAVE_12_(case SAMPR_12:)
122 HW_HAVE_16_(case SAMPR_16:)
123 HW_HAVE_22_(case SAMPR_22:)
124 HW_HAVE_24_(case SAMPR_24:)
125 HW_HAVE_32_(case SAMPR_32:)
126 HW_HAVE_44_(case SAMPR_44:)
127 HW_HAVE_48_(case SAMPR_48:)
128 HW_HAVE_64_(case SAMPR_64:)
129 HW_HAVE_88_(case SAMPR_88:)
130 HW_HAVE_96_(case SAMPR_96:)
131 break;
132 default:
133 frequency = SAMPR_44;
136 pcm_frequency = frequency;
139 extern int sim_volume; /* in firmware/sound.c */
140 void write_to_soundcard(struct pcm_udata *udata) {
141 if (cvt.needed) {
142 Uint32 rd = udata->num_in;
143 Uint32 wr = (double)rd * cvt.len_ratio;
145 if (wr > udata->num_out) {
146 wr = udata->num_out;
147 rd = (double)wr / cvt.len_ratio;
149 if (rd > udata->num_in)
151 rd = udata->num_in;
152 wr = (double)rd * cvt.len_ratio;
156 if (wr == 0 || rd == 0)
158 udata->num_out = udata->num_in = 0;
159 return;
162 if (cvt_status > 0) {
163 cvt.len = rd * pcm_sample_bytes;
164 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
166 memcpy(cvt.buf, pcm_data, cvt.len);
168 SDL_ConvertAudio(&cvt);
169 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
171 udata->num_in = cvt.len / pcm_sample_bytes;
172 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
174 if (udata->debug != NULL) {
175 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
178 free(cvt.buf);
180 else {
181 /* Convert is bad, so do silence */
182 Uint32 num = wr*obtained.channels;
183 udata->num_in = rd;
184 udata->num_out = wr;
186 switch (pcm_channel_bytes)
188 case 1:
190 Uint8 *stream = udata->stream;
191 while (num-- > 0)
192 *stream++ = obtained.silence;
193 break;
195 case 2:
197 Uint16 *stream = (Uint16 *)udata->stream;
198 while (num-- > 0)
199 *stream++ = obtained.silence;
200 break;
204 if (udata->debug != NULL) {
205 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
208 } else {
209 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
210 SDL_MixAudio(udata->stream, pcm_data,
211 udata->num_out * pcm_sample_bytes, sim_volume);
213 if (udata->debug != NULL) {
214 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
215 udata->debug);
220 void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
222 udata->stream = stream;
224 /* Write what we have in the PCM buffer */
225 if (pcm_data_size > 0)
226 goto start;
228 /* Audio card wants more? Get some more then. */
229 while (len > 0) {
230 if ((ssize_t)pcm_data_size <= 0) {
231 pcm_data_size = 0;
233 if (pcm_callback_for_more)
234 pcm_callback_for_more(&pcm_data, &pcm_data_size);
237 if (pcm_data_size > 0) {
238 start:
239 udata->num_in = pcm_data_size / pcm_sample_bytes;
240 udata->num_out = len / pcm_sample_bytes;
242 write_to_soundcard(udata);
244 udata->num_in *= pcm_sample_bytes;
245 udata->num_out *= pcm_sample_bytes;
247 pcm_data += udata->num_in;
248 pcm_data_size -= udata->num_in;
249 udata->stream += udata->num_out;
250 len -= udata->num_out;
251 } else {
252 DEBUGF("sdl_audio_callback: No Data.\n");
253 pcm_play_dma_stop();
254 pcm_play_dma_stopped_callback();
255 break;
260 const void * pcm_play_dma_get_peak_buffer(int *count)
262 uintptr_t addr = (uintptr_t)pcm_data;
263 *count = pcm_data_size / 4;
264 return (void *)((addr + 2) & ~3);
267 #ifdef HAVE_RECORDING
268 void pcm_rec_lock(void)
272 void pcm_rec_unlock(void)
276 void pcm_rec_dma_init(void)
280 void pcm_rec_dma_close(void)
284 void pcm_rec_dma_start(void *start, size_t size)
286 (void)start;
287 (void)size;
290 void pcm_rec_dma_stop(void)
294 void pcm_record_more(void *start, size_t size)
296 (void)start;
297 (void)size;
300 unsigned long pcm_rec_status(void)
302 return 0;
305 const void * pcm_rec_dma_get_peak_buffer(int *count)
307 *count = 0;
308 return NULL;
311 #endif /* HAVE_RECORDING */
313 void pcm_play_dma_init(void)
315 SDL_AudioSpec wanted_spec;
316 udata.debug = NULL;
318 if (debug_audio) {
319 udata.debug = fopen("audiodebug.raw", "wb");
322 /* Set 16-bit stereo audio at 44Khz */
323 wanted_spec.freq = 44100;
324 wanted_spec.format = AUDIO_S16SYS;
325 wanted_spec.channels = 2;
326 wanted_spec.samples = 2048;
327 wanted_spec.callback =
328 (void (SDLCALL *)(void *userdata,
329 Uint8 *stream, int len))sdl_audio_callback;
330 wanted_spec.userdata = &udata;
332 /* Open the audio device and start playing sound! */
333 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
334 fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
335 return;
338 switch (obtained.format)
340 case AUDIO_U8:
341 case AUDIO_S8:
342 pcm_channel_bytes = 1;
343 break;
344 case AUDIO_U16LSB:
345 case AUDIO_S16LSB:
346 case AUDIO_U16MSB:
347 case AUDIO_S16MSB:
348 pcm_channel_bytes = 2;
349 break;
350 default:
351 fprintf(stderr, "Unknown sample format obtained: %u\n",
352 (unsigned)obtained.format);
353 return;
356 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
358 pcm_apply_settings_nolock();
361 void pcm_postinit(void)