FS#11968 by Peter Lecky - Slovak language update
[maemo-rb.git] / firmware / target / hosted / sdl / pcm-sdl.c
blob7780083b993f4fb423693cb07ed1cddab2ad8287
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 #ifdef HAVE_SPDIF_IN
37 #include "spdif.h"
38 #endif
39 #endif
41 #include "pcm.h"
42 #include "pcm_sampr.h"
44 /*#define LOGF_ENABLE*/
45 #include "logf.h"
47 #ifdef DEBUG
48 #include <stdio.h>
49 extern bool debug_audio;
50 #endif
52 static int sim_volume = 0;
54 #if CONFIG_CODEC == SWCODEC
55 static int cvt_status = -1;
57 static Uint8* pcm_data;
58 static size_t pcm_data_size;
59 static size_t pcm_sample_bytes;
60 static size_t pcm_channel_bytes;
62 static struct pcm_udata
64 Uint8 *stream;
65 Uint32 num_in;
66 Uint32 num_out;
67 #ifdef DEBUG
68 FILE *debug;
69 #endif
70 } udata;
72 static SDL_AudioSpec obtained;
73 static SDL_AudioCVT cvt;
75 void pcm_play_lock(void)
77 SDL_LockAudio();
80 void pcm_play_unlock(void)
82 SDL_UnlockAudio();
85 static void pcm_dma_apply_settings_nolock(void)
87 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
88 obtained.format, obtained.channels, obtained.freq);
90 if (cvt_status < 0) {
91 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
95 void pcm_dma_apply_settings(void)
97 pcm_play_lock();
98 pcm_dma_apply_settings_nolock();
99 pcm_play_unlock();
102 void pcm_play_dma_start(const void *addr, size_t size)
104 pcm_dma_apply_settings_nolock();
106 pcm_data = (Uint8 *) addr;
107 pcm_data_size = size;
109 SDL_PauseAudio(0);
112 void pcm_play_dma_stop(void)
114 SDL_PauseAudio(1);
115 #ifdef DEBUG
116 if (udata.debug != NULL) {
117 fclose(udata.debug);
118 udata.debug = NULL;
119 DEBUGF("Audio debug file closed\n");
121 #endif
124 void pcm_play_dma_pause(bool pause)
126 if (pause)
127 SDL_PauseAudio(1);
128 else
129 SDL_PauseAudio(0);
132 size_t pcm_get_bytes_waiting(void)
134 return pcm_data_size;
137 static void write_to_soundcard(struct pcm_udata *udata)
139 #ifdef DEBUG
140 if (debug_audio && (udata->debug == NULL)) {
141 udata->debug = fopen("audiodebug.raw", "ab");
142 DEBUGF("Audio debug file open\n");
144 #endif
145 if (cvt.needed) {
146 Uint32 rd = udata->num_in;
147 Uint32 wr = (double)rd * cvt.len_ratio;
149 if (wr > udata->num_out) {
150 wr = udata->num_out;
151 rd = (double)wr / cvt.len_ratio;
153 if (rd > udata->num_in)
155 rd = udata->num_in;
156 wr = (double)rd * cvt.len_ratio;
160 if (wr == 0 || rd == 0)
162 udata->num_out = udata->num_in = 0;
163 return;
166 if (cvt_status > 0) {
167 cvt.len = rd * pcm_sample_bytes;
168 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
170 memcpy(cvt.buf, pcm_data, cvt.len);
172 SDL_ConvertAudio(&cvt);
173 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
175 udata->num_in = cvt.len / pcm_sample_bytes;
176 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
178 #ifdef DEBUG
179 if (udata->debug != NULL) {
180 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
182 #endif
183 free(cvt.buf);
185 else {
186 /* Convert is bad, so do silence */
187 Uint32 num = wr*obtained.channels;
188 udata->num_in = rd;
189 udata->num_out = wr;
191 switch (pcm_channel_bytes)
193 case 1:
195 Uint8 *stream = udata->stream;
196 while (num-- > 0)
197 *stream++ = obtained.silence;
198 break;
200 case 2:
202 Uint16 *stream = (Uint16 *)udata->stream;
203 while (num-- > 0)
204 *stream++ = obtained.silence;
205 break;
208 #ifdef DEBUG
209 if (udata->debug != NULL) {
210 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
212 #endif
214 } else {
215 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
216 SDL_MixAudio(udata->stream, pcm_data,
217 udata->num_out * pcm_sample_bytes, sim_volume);
218 #ifdef DEBUG
219 if (udata->debug != NULL) {
220 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
221 udata->debug);
223 #endif
227 static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
229 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size);
230 udata->stream = stream;
232 /* Write what we have in the PCM buffer */
233 if (pcm_data_size > 0)
234 goto start;
236 /* Audio card wants more? Get some more then. */
237 while (len > 0) {
238 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
239 start:
240 if (pcm_data_size != 0) {
241 udata->num_in = pcm_data_size / pcm_sample_bytes;
242 udata->num_out = len / pcm_sample_bytes;
244 write_to_soundcard(udata);
246 udata->num_in *= pcm_sample_bytes;
247 udata->num_out *= pcm_sample_bytes;
249 pcm_data += udata->num_in;
250 pcm_data_size -= udata->num_in;
251 udata->stream += udata->num_out;
252 len -= udata->num_out;
253 } else {
254 DEBUGF("sdl_audio_callback: No Data.\n");
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 const void * pcm_rec_dma_get_peak_buffer(void)
296 return NULL;
299 void audiohw_set_recvol(int left, int right, int type)
301 (void)left;
302 (void)right;
303 (void)type;
306 #ifdef HAVE_SPDIF_IN
307 unsigned long spdif_measure_frequency(void)
309 return 0;
311 #endif
313 #endif /* HAVE_RECORDING */
315 void pcm_play_dma_init(void)
317 if (SDL_InitSubSystem(SDL_INIT_AUDIO))
319 DEBUGF("Could not initialize SDL audio subsystem!\n");
320 return;
323 SDL_AudioSpec wanted_spec;
324 #ifdef DEBUG
325 udata.debug = NULL;
326 if (debug_audio) {
327 udata.debug = fopen("audiodebug.raw", "wb");
328 DEBUGF("Audio debug file open\n");
330 #endif
331 /* Set 16-bit stereo audio at 44Khz */
332 wanted_spec.freq = 44100;
333 wanted_spec.format = AUDIO_S16SYS;
334 wanted_spec.channels = 2;
335 wanted_spec.samples = 2048;
336 wanted_spec.callback =
337 (void (SDLCALL *)(void *userdata,
338 Uint8 *stream, int len))sdl_audio_callback;
339 wanted_spec.userdata = &udata;
341 /* Open the audio device and start playing sound! */
342 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
343 DEBUGF("Unable to open audio: %s\n", SDL_GetError());
344 return;
347 switch (obtained.format)
349 case AUDIO_U8:
350 case AUDIO_S8:
351 pcm_channel_bytes = 1;
352 break;
353 case AUDIO_U16LSB:
354 case AUDIO_S16LSB:
355 case AUDIO_U16MSB:
356 case AUDIO_S16MSB:
357 pcm_channel_bytes = 2;
358 break;
359 default:
360 DEBUGF("Unknown sample format obtained: %u\n",
361 (unsigned)obtained.format);
362 return;
365 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
367 pcm_dma_apply_settings_nolock();
370 void pcm_postinit(void)
374 void pcm_set_mixer_volume(int volume)
376 sim_volume = volume;
379 #endif /* CONFIG_CODEC == SWCODEC */