Gigabeat S: Fully enable access to hardware tone controls and 3-D effect feature...
[kugel-rb.git] / uisimulator / sdl / sound.c
blob0f8d5d4934ec72407fccf38d31d683e8d2805644
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 "kernel.h"
28 #include "sound.h"
29 #include "audiohw.h"
31 #include "pcm.h"
32 #include "pcm_sampr.h"
33 #include "SDL.h"
35 /*#define LOGF_ENABLE*/
36 #include "logf.h"
38 static int sim_volume = 0;
40 #if CONFIG_CODEC == SWCODEC
41 static int cvt_status = -1;
43 static Uint8* pcm_data;
44 static size_t pcm_data_size;
45 static size_t pcm_sample_bytes;
46 static size_t pcm_channel_bytes;
48 static struct pcm_udata
50 Uint8 *stream;
51 Uint32 num_in;
52 Uint32 num_out;
53 FILE *debug;
54 } udata;
56 static SDL_AudioSpec obtained;
57 static SDL_AudioCVT cvt;
59 extern bool debug_audio;
61 #ifndef MIN
62 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
63 #endif
65 void pcm_play_lock(void)
67 SDL_LockAudio();
70 void pcm_play_unlock(void)
72 SDL_UnlockAudio();
75 static void pcm_dma_apply_settings_nolock(void)
77 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
78 obtained.format, obtained.channels, obtained.freq);
80 if (cvt_status < 0) {
81 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
85 void pcm_dma_apply_settings(void)
87 pcm_play_lock();
88 pcm_dma_apply_settings_nolock();
89 pcm_play_unlock();
92 void pcm_play_dma_start(const void *addr, size_t size)
94 pcm_dma_apply_settings_nolock();
96 pcm_data = (Uint8 *) addr;
97 pcm_data_size = size;
99 SDL_PauseAudio(0);
102 void pcm_play_dma_stop(void)
104 SDL_PauseAudio(1);
105 if (udata.debug != NULL) {
106 fclose(udata.debug);
107 udata.debug = NULL;
108 DEBUGF("Audio debug file closed\n");
112 void pcm_play_dma_pause(bool pause)
114 if (pause)
115 SDL_PauseAudio(1);
116 else
117 SDL_PauseAudio(0);
120 size_t pcm_get_bytes_waiting(void)
122 return pcm_data_size;
125 extern int sim_volume; /* in firmware/sound.c */
126 static void write_to_soundcard(struct pcm_udata *udata) {
127 if (debug_audio && (udata->debug == NULL)) {
128 udata->debug = fopen("audiodebug.raw", "ab");
129 DEBUGF("Audio debug file open\n");
132 if (cvt.needed) {
133 Uint32 rd = udata->num_in;
134 Uint32 wr = (double)rd * cvt.len_ratio;
136 if (wr > udata->num_out) {
137 wr = udata->num_out;
138 rd = (double)wr / cvt.len_ratio;
140 if (rd > udata->num_in)
142 rd = udata->num_in;
143 wr = (double)rd * cvt.len_ratio;
147 if (wr == 0 || rd == 0)
149 udata->num_out = udata->num_in = 0;
150 return;
153 if (cvt_status > 0) {
154 cvt.len = rd * pcm_sample_bytes;
155 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
157 memcpy(cvt.buf, pcm_data, cvt.len);
159 SDL_ConvertAudio(&cvt);
160 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
162 udata->num_in = cvt.len / pcm_sample_bytes;
163 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
165 if (udata->debug != NULL) {
166 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
169 free(cvt.buf);
171 else {
172 /* Convert is bad, so do silence */
173 Uint32 num = wr*obtained.channels;
174 udata->num_in = rd;
175 udata->num_out = wr;
177 switch (pcm_channel_bytes)
179 case 1:
181 Uint8 *stream = udata->stream;
182 while (num-- > 0)
183 *stream++ = obtained.silence;
184 break;
186 case 2:
188 Uint16 *stream = (Uint16 *)udata->stream;
189 while (num-- > 0)
190 *stream++ = obtained.silence;
191 break;
195 if (udata->debug != NULL) {
196 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
199 } else {
200 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
201 SDL_MixAudio(udata->stream, pcm_data,
202 udata->num_out * pcm_sample_bytes, sim_volume);
204 if (udata->debug != NULL) {
205 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
206 udata->debug);
211 static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
213 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size);
214 udata->stream = stream;
216 /* Write what we have in the PCM buffer */
217 if (pcm_data_size > 0)
218 goto start;
220 /* Audio card wants more? Get some more then. */
221 while (len > 0) {
222 if ((ssize_t)pcm_data_size <= 0) {
223 pcm_data_size = 0;
224 if (pcm_callback_for_more)
225 pcm_callback_for_more(&pcm_data, &pcm_data_size);
228 if (pcm_data_size > 0) {
229 start:
230 udata->num_in = pcm_data_size / pcm_sample_bytes;
231 udata->num_out = len / pcm_sample_bytes;
233 write_to_soundcard(udata);
235 udata->num_in *= pcm_sample_bytes;
236 udata->num_out *= pcm_sample_bytes;
238 pcm_data += udata->num_in;
239 pcm_data_size -= udata->num_in;
240 udata->stream += udata->num_out;
241 len -= udata->num_out;
242 } else {
243 DEBUGF("sdl_audio_callback: No Data.\n");
244 pcm_play_dma_stop();
245 pcm_play_dma_stopped_callback();
246 break;
251 const void * pcm_play_dma_get_peak_buffer(int *count)
253 uintptr_t addr = (uintptr_t)pcm_data;
254 *count = pcm_data_size / 4;
255 return (void *)((addr + 2) & ~3);
258 #ifdef HAVE_RECORDING
259 void pcm_rec_lock(void)
263 void pcm_rec_unlock(void)
267 void pcm_rec_dma_init(void)
271 void pcm_rec_dma_close(void)
275 void pcm_rec_dma_start(void *start, size_t size)
277 (void)start;
278 (void)size;
281 void pcm_rec_dma_stop(void)
285 void pcm_rec_dma_record_more(void *start, size_t size)
287 (void)start;
288 (void)size;
291 unsigned long pcm_rec_status(void)
293 return 0;
296 const void * pcm_rec_dma_get_peak_buffer(void)
298 return NULL;
301 #endif /* HAVE_RECORDING */
303 void pcm_play_dma_init(void)
305 SDL_AudioSpec wanted_spec;
306 udata.debug = NULL;
308 if (debug_audio) {
309 udata.debug = fopen("audiodebug.raw", "wb");
310 DEBUGF("Audio debug file open\n");
313 /* Set 16-bit stereo audio at 44Khz */
314 wanted_spec.freq = 44100;
315 wanted_spec.format = AUDIO_S16SYS;
316 wanted_spec.channels = 2;
317 wanted_spec.samples = 2048;
318 wanted_spec.callback =
319 (void (SDLCALL *)(void *userdata,
320 Uint8 *stream, int len))sdl_audio_callback;
321 wanted_spec.userdata = &udata;
323 /* Open the audio device and start playing sound! */
324 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
325 fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
326 return;
329 switch (obtained.format)
331 case AUDIO_U8:
332 case AUDIO_S8:
333 pcm_channel_bytes = 1;
334 break;
335 case AUDIO_U16LSB:
336 case AUDIO_S16LSB:
337 case AUDIO_U16MSB:
338 case AUDIO_S16MSB:
339 pcm_channel_bytes = 2;
340 break;
341 default:
342 fprintf(stderr, "Unknown sample format obtained: %u\n",
343 (unsigned)obtained.format);
344 return;
347 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
349 pcm_dma_apply_settings_nolock();
352 void pcm_postinit(void)
356 #endif /* CONFIG_CODEC == SWCODEC */
359 * Audio Hardware api. Make them do nothing as we cannot properly simulate with
360 * SDL. if we used DSP we would run code that doesn't actually run on the target
362 void audiohw_set_volume(int volume)
364 sim_volume = SDL_MIX_MAXVOLUME * ((volume - VOLUME_MIN) / 10) / (VOLUME_RANGE / 10);
366 #if defined(AUDIOHW_HAVE_PRESCALER)
367 void audiohw_set_prescaler(int value) { (void)value; }
368 #endif
369 #if defined(AUDIOHW_HAVE_BALANCE)
370 void audiohw_set_balance(int value) { (void)value; }
371 #endif
372 #if defined(AUDIOHW_HAVE_BASS)
373 void audiohw_set_bass(int value) { (void)value; }
374 #endif
375 #if defined(AUDIOHW_HAVE_TREBLE)
376 void audiohw_set_treble(int value) { (void)value; }
377 #endif
378 #if CONFIG_CODEC != SWCODEC
379 void audiohw_set_channel(int value) { (void)value; }
380 void audiohw_set_stereo_width(int value){ (void)value; }
381 #endif
382 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
383 void audiohw_set_bass_cutoff(int value) { (void)value; }
384 #endif
385 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
386 void audiohw_set_treble_cutoff(int value){ (void)value; }
387 #endif
388 /* EQ-based tone controls */
389 #if defined(AUDIOHW_HAVE_EQ)
390 void audiohw_set_eq_band_gain(unsigned int band, int value)
391 { (void)band; (void)value; }
392 #endif
393 #if defined(AUDIOHW_HAVE_EQ_FREQUENCY)
394 void audiohw_set_eq_band_frequency(unsigned int band, int value)
395 { (void)band; (void)value; }
396 #endif
397 #if defined(AUDIOHW_HAVE_EQ_WIDTH)
398 void audiohw_set_eq_band_width(unsigned int band, int value)
399 { (void)band; (void)value; }
400 #endif
401 #if defined(AUDIOHW_HAVE_DEPTH_3D)
402 void audiohw_set_depth_3d(int value)
403 { (void)value; }
404 #endif
405 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
406 int mas_codec_readreg(int reg)
408 (void)reg;
409 return 0;
412 int mas_codec_writereg(int reg, unsigned int val)
414 (void)reg;
415 (void)val;
416 return 0;
418 int mas_writemem(int bank, int addr, const unsigned long* src, int len)
420 (void)bank;
421 (void)addr;
422 (void)src;
423 (void)len;
424 return 0;
426 #endif