Implement a C version lcd-as-memframe.c and move it and the asm to firmware/asm.
[maemo-rb.git] / firmware / target / hosted / sdl / pcm-sdl.c
blob020928d572116dba3fa97c86783aa6068e65624d
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"
33 #include "panic.h"
35 #ifdef HAVE_RECORDING
36 #include "audiohw.h"
37 #ifdef HAVE_SPDIF_IN
38 #include "spdif.h"
39 #endif
40 #endif
42 #include "pcm.h"
43 #include "pcm-internal.h"
44 #include "pcm_sampr.h"
46 /*#define LOGF_ENABLE*/
47 #include "logf.h"
49 #ifdef DEBUG
50 #include <stdio.h>
51 extern bool debug_audio;
52 #endif
54 static int sim_volume = 0;
56 #if CONFIG_CODEC == SWCODEC
57 static int cvt_status = -1;
59 static Uint8* pcm_data;
60 static size_t pcm_data_size;
61 static size_t pcm_sample_bytes;
62 static size_t pcm_channel_bytes;
64 static struct pcm_udata
66 Uint8 *stream;
67 Uint32 num_in;
68 Uint32 num_out;
69 #ifdef DEBUG
70 FILE *debug;
71 #endif
72 } udata;
74 static SDL_AudioSpec obtained;
75 static SDL_AudioCVT cvt;
76 static int audio_locked = 0;
77 static SDL_mutex *audio_lock;
79 void pcm_play_lock(void)
81 if (++audio_locked == 1)
82 SDL_LockMutex(audio_lock);
85 void pcm_play_unlock(void)
87 if (--audio_locked == 0)
88 SDL_UnlockMutex(audio_lock);
91 static void pcm_dma_apply_settings_nolock(void)
93 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_sampr,
94 obtained.format, obtained.channels, obtained.freq);
96 if (cvt_status < 0) {
97 cvt.len_ratio = (double)obtained.freq / (double)pcm_sampr;
101 void pcm_dma_apply_settings(void)
103 pcm_play_lock();
104 pcm_dma_apply_settings_nolock();
105 pcm_play_unlock();
108 void pcm_play_dma_start(const void *addr, size_t size)
110 pcm_dma_apply_settings_nolock();
112 pcm_data = (Uint8 *) addr;
113 pcm_data_size = size;
115 SDL_PauseAudio(0);
118 void pcm_play_dma_stop(void)
120 SDL_PauseAudio(1);
121 #ifdef DEBUG
122 if (udata.debug != NULL) {
123 fclose(udata.debug);
124 udata.debug = NULL;
125 DEBUGF("Audio debug file closed\n");
127 #endif
130 void pcm_play_dma_pause(bool pause)
132 if (pause)
133 SDL_PauseAudio(1);
134 else
135 SDL_PauseAudio(0);
138 size_t pcm_get_bytes_waiting(void)
140 return pcm_data_size;
143 static void write_to_soundcard(struct pcm_udata *udata)
145 #ifdef DEBUG
146 if (debug_audio && (udata->debug == NULL)) {
147 udata->debug = fopen("audiodebug.raw", "ab");
148 DEBUGF("Audio debug file open\n");
150 #endif
151 if (cvt.needed) {
152 Uint32 rd = udata->num_in;
153 Uint32 wr = (double)rd * cvt.len_ratio;
155 if (wr > udata->num_out) {
156 wr = udata->num_out;
157 rd = (double)wr / cvt.len_ratio;
159 if (rd > udata->num_in)
161 rd = udata->num_in;
162 wr = (double)rd * cvt.len_ratio;
166 if (wr == 0 || rd == 0)
168 udata->num_out = udata->num_in = 0;
169 return;
172 if (cvt_status > 0) {
173 cvt.len = rd * pcm_sample_bytes;
174 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
176 memcpy(cvt.buf, pcm_data, cvt.len);
178 SDL_ConvertAudio(&cvt);
179 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
181 udata->num_in = cvt.len / pcm_sample_bytes;
182 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
184 #ifdef DEBUG
185 if (udata->debug != NULL) {
186 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
188 #endif
189 free(cvt.buf);
191 else {
192 /* Convert is bad, so do silence */
193 Uint32 num = wr*obtained.channels;
194 udata->num_in = rd;
195 udata->num_out = wr;
197 switch (pcm_channel_bytes)
199 case 1:
201 Uint8 *stream = udata->stream;
202 while (num-- > 0)
203 *stream++ = obtained.silence;
204 break;
206 case 2:
208 Uint16 *stream = (Uint16 *)udata->stream;
209 while (num-- > 0)
210 *stream++ = obtained.silence;
211 break;
214 #ifdef DEBUG
215 if (udata->debug != NULL) {
216 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
218 #endif
220 } else {
221 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
222 SDL_MixAudio(udata->stream, pcm_data,
223 udata->num_out * pcm_sample_bytes, sim_volume);
224 #ifdef DEBUG
225 if (udata->debug != NULL) {
226 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
227 udata->debug);
229 #endif
233 static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
235 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size);
237 bool new_buffer = false;
238 udata->stream = stream;
240 SDL_LockMutex(audio_lock);
242 /* Write what we have in the PCM buffer */
243 if (pcm_data_size > 0)
244 goto start;
246 /* Audio card wants more? Get some more then. */
247 while (len > 0) {
248 new_buffer = true;
249 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
250 start:
251 if (pcm_data_size != 0) {
252 udata->num_in = pcm_data_size / pcm_sample_bytes;
253 udata->num_out = len / pcm_sample_bytes;
255 write_to_soundcard(udata);
257 udata->num_in *= pcm_sample_bytes;
258 udata->num_out *= pcm_sample_bytes;
261 if (new_buffer)
263 new_buffer = false;
264 pcm_play_dma_started_callback();
266 if ((size_t)len > udata->num_out)
268 int delay = pcm_data_size*250 / pcm_sampr - 1;
270 if (delay > 0)
272 SDL_UnlockMutex(audio_lock);
273 SDL_Delay(delay);
274 SDL_LockMutex(audio_lock);
276 if (!pcm_is_playing())
277 break;
282 pcm_data += udata->num_in;
283 pcm_data_size -= udata->num_in;
284 udata->stream += udata->num_out;
285 len -= udata->num_out;
286 } else {
287 DEBUGF("sdl_audio_callback: No Data.\n");
288 break;
292 SDL_UnlockMutex(audio_lock);
295 const void * pcm_play_dma_get_peak_buffer(int *count)
297 uintptr_t addr = (uintptr_t)pcm_data;
298 *count = pcm_data_size / 4;
299 return (void *)((addr + 2) & ~3);
302 #ifdef HAVE_RECORDING
303 void pcm_rec_lock(void)
307 void pcm_rec_unlock(void)
311 void pcm_rec_dma_init(void)
315 void pcm_rec_dma_close(void)
319 void pcm_rec_dma_start(void *start, size_t size)
321 (void)start;
322 (void)size;
325 void pcm_rec_dma_stop(void)
329 const void * pcm_rec_dma_get_peak_buffer(void)
331 return NULL;
334 void audiohw_set_recvol(int left, int right, int type)
336 (void)left;
337 (void)right;
338 (void)type;
341 #ifdef HAVE_SPDIF_IN
342 unsigned long spdif_measure_frequency(void)
344 return 0;
346 #endif
348 #endif /* HAVE_RECORDING */
350 void pcm_play_dma_init(void)
352 if (SDL_InitSubSystem(SDL_INIT_AUDIO))
354 DEBUGF("Could not initialize SDL audio subsystem!\n");
355 return;
358 audio_lock = SDL_CreateMutex();
360 if (!audio_lock)
362 panicf("Could not create audio_lock\n");
363 return;
366 SDL_AudioSpec wanted_spec;
367 #ifdef DEBUG
368 udata.debug = NULL;
369 if (debug_audio) {
370 udata.debug = fopen("audiodebug.raw", "wb");
371 DEBUGF("Audio debug file open\n");
373 #endif
374 /* Set 16-bit stereo audio at 44Khz */
375 wanted_spec.freq = 44100;
376 wanted_spec.format = AUDIO_S16SYS;
377 wanted_spec.channels = 2;
378 wanted_spec.samples = 2048;
379 wanted_spec.callback =
380 (void (SDLCALL *)(void *userdata,
381 Uint8 *stream, int len))sdl_audio_callback;
382 wanted_spec.userdata = &udata;
384 /* Open the audio device and start playing sound! */
385 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
386 DEBUGF("Unable to open audio: %s\n", SDL_GetError());
387 return;
390 switch (obtained.format)
392 case AUDIO_U8:
393 case AUDIO_S8:
394 pcm_channel_bytes = 1;
395 break;
396 case AUDIO_U16LSB:
397 case AUDIO_S16LSB:
398 case AUDIO_U16MSB:
399 case AUDIO_S16MSB:
400 pcm_channel_bytes = 2;
401 break;
402 default:
403 DEBUGF("Unknown sample format obtained: %u\n",
404 (unsigned)obtained.format);
405 return;
408 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
410 pcm_dma_apply_settings_nolock();
413 void pcm_play_dma_postinit(void)
417 void pcm_set_mixer_volume(int volume)
419 sim_volume = volume;
422 #endif /* CONFIG_CODEC == SWCODEC */