Simulator: build recording code
[kugel-rb.git] / firmware / target / hosted / sdl / pcm-sdl.c
blob55919802176d7e37bbeed284835062784401c330
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Nick Lanham
11 * Copyright (C) 2010 by Thomas Martitz
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include "autoconf.h"
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"
34 #ifdef HAVE_RECORDING
35 #include "audiohw.h"
36 #endif
38 #include "pcm.h"
39 #include "pcm_sampr.h"
41 /*#define LOGF_ENABLE*/
42 #include "logf.h"
44 #ifdef DEBUG
45 #include <stdio.h>
46 extern bool debug_audio;
47 #endif
49 static int sim_volume = 0;
51 #if CONFIG_CODEC == SWCODEC
52 static int cvt_status = -1;
54 static Uint8* pcm_data;
55 static size_t pcm_data_size;
56 static size_t pcm_sample_bytes;
57 static size_t pcm_channel_bytes;
59 static struct pcm_udata
61 Uint8 *stream;
62 Uint32 num_in;
63 Uint32 num_out;
64 #ifdef DEBUG
65 FILE *debug;
66 #endif
67 } udata;
69 static SDL_AudioSpec obtained;
70 static SDL_AudioCVT cvt;
72 void pcm_play_lock(void)
74 SDL_LockAudio();
77 void pcm_play_unlock(void)
79 SDL_UnlockAudio();
82 static void pcm_dma_apply_settings_nolock(void)
84 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
85 obtained.format, obtained.channels, obtained.freq);
87 if (cvt_status < 0) {
88 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
92 void pcm_dma_apply_settings(void)
94 pcm_play_lock();
95 pcm_dma_apply_settings_nolock();
96 pcm_play_unlock();
99 void pcm_play_dma_start(const void *addr, size_t size)
101 pcm_dma_apply_settings_nolock();
103 pcm_data = (Uint8 *) addr;
104 pcm_data_size = size;
106 SDL_PauseAudio(0);
109 void pcm_play_dma_stop(void)
111 SDL_PauseAudio(1);
112 #ifdef DEBUG
113 if (udata.debug != NULL) {
114 fclose(udata.debug);
115 udata.debug = NULL;
116 DEBUGF("Audio debug file closed\n");
118 #endif
121 void pcm_play_dma_pause(bool pause)
123 if (pause)
124 SDL_PauseAudio(1);
125 else
126 SDL_PauseAudio(0);
129 size_t pcm_get_bytes_waiting(void)
131 return pcm_data_size;
134 static void write_to_soundcard(struct pcm_udata *udata)
136 #ifdef DEBUG
137 if (debug_audio && (udata->debug == NULL)) {
138 udata->debug = fopen("audiodebug.raw", "ab");
139 DEBUGF("Audio debug file open\n");
141 #endif
142 if (cvt.needed) {
143 Uint32 rd = udata->num_in;
144 Uint32 wr = (double)rd * cvt.len_ratio;
146 if (wr > udata->num_out) {
147 wr = udata->num_out;
148 rd = (double)wr / cvt.len_ratio;
150 if (rd > udata->num_in)
152 rd = udata->num_in;
153 wr = (double)rd * cvt.len_ratio;
157 if (wr == 0 || rd == 0)
159 udata->num_out = udata->num_in = 0;
160 return;
163 if (cvt_status > 0) {
164 cvt.len = rd * pcm_sample_bytes;
165 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
167 memcpy(cvt.buf, pcm_data, cvt.len);
169 SDL_ConvertAudio(&cvt);
170 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
172 udata->num_in = cvt.len / pcm_sample_bytes;
173 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
175 #ifdef DEBUG
176 if (udata->debug != NULL) {
177 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
179 #endif
180 free(cvt.buf);
182 else {
183 /* Convert is bad, so do silence */
184 Uint32 num = wr*obtained.channels;
185 udata->num_in = rd;
186 udata->num_out = wr;
188 switch (pcm_channel_bytes)
190 case 1:
192 Uint8 *stream = udata->stream;
193 while (num-- > 0)
194 *stream++ = obtained.silence;
195 break;
197 case 2:
199 Uint16 *stream = (Uint16 *)udata->stream;
200 while (num-- > 0)
201 *stream++ = obtained.silence;
202 break;
205 #ifdef DEBUG
206 if (udata->debug != NULL) {
207 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
209 #endif
211 } else {
212 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
213 SDL_MixAudio(udata->stream, pcm_data,
214 udata->num_out * pcm_sample_bytes, sim_volume);
215 #ifdef DEBUG
216 if (udata->debug != NULL) {
217 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
218 udata->debug);
220 #endif
224 static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
226 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size);
227 udata->stream = stream;
229 /* Write what we have in the PCM buffer */
230 if (pcm_data_size > 0)
231 goto start;
233 /* Audio card wants more? Get some more then. */
234 while (len > 0) {
235 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
236 start:
237 if (pcm_data_size != 0) {
238 udata->num_in = pcm_data_size / pcm_sample_bytes;
239 udata->num_out = len / pcm_sample_bytes;
241 write_to_soundcard(udata);
243 udata->num_in *= pcm_sample_bytes;
244 udata->num_out *= pcm_sample_bytes;
246 pcm_data += udata->num_in;
247 pcm_data_size -= udata->num_in;
248 udata->stream += udata->num_out;
249 len -= udata->num_out;
250 } else {
251 DEBUGF("sdl_audio_callback: No Data.\n");
252 break;
257 const void * pcm_play_dma_get_peak_buffer(int *count)
259 uintptr_t addr = (uintptr_t)pcm_data;
260 *count = pcm_data_size / 4;
261 return (void *)((addr + 2) & ~3);
264 #ifdef HAVE_RECORDING
265 void pcm_rec_lock(void)
269 void pcm_rec_unlock(void)
273 void pcm_rec_dma_init(void)
277 void pcm_rec_dma_close(void)
281 void pcm_rec_dma_start(void *start, size_t size)
283 (void)start;
284 (void)size;
287 void pcm_rec_dma_stop(void)
291 const void * pcm_rec_dma_get_peak_buffer(void)
293 return NULL;
296 void audiohw_set_recvol(int left, int right, int type)
298 (void)left;
299 (void)right;
300 (void)type;
304 #endif /* HAVE_RECORDING */
306 void pcm_play_dma_init(void)
308 if (SDL_InitSubSystem(SDL_INIT_AUDIO))
310 DEBUGF("Could not initialize SDL audio subsystem!\n");
311 return;
314 SDL_AudioSpec wanted_spec;
315 #ifdef DEBUG
316 udata.debug = NULL;
317 if (debug_audio) {
318 udata.debug = fopen("audiodebug.raw", "wb");
319 DEBUGF("Audio debug file open\n");
321 #endif
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 DEBUGF("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 DEBUGF("Unknown sample format obtained: %u\n",
352 (unsigned)obtained.format);
353 return;
356 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
358 pcm_dma_apply_settings_nolock();
361 void pcm_postinit(void)
365 void pcm_set_mixer_volume(int volume)
367 sim_volume = volume;
370 #endif /* CONFIG_CODEC == SWCODEC */