1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
43 #include "pcm-internal.h"
44 #include "pcm_sampr.h"
46 /*#define LOGF_ENABLE*/
51 extern bool debug_audio
;
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
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
);
97 cvt
.len_ratio
= (double)obtained
.freq
/ (double)pcm_sampr
;
101 void pcm_dma_apply_settings(void)
104 pcm_dma_apply_settings_nolock();
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
;
118 void pcm_play_dma_stop(void)
122 if (udata
.debug
!= NULL
) {
125 DEBUGF("Audio debug file closed\n");
130 void pcm_play_dma_pause(bool pause
)
138 size_t pcm_get_bytes_waiting(void)
140 return pcm_data_size
;
143 static void write_to_soundcard(struct pcm_udata
*udata
)
146 if (debug_audio
&& (udata
->debug
== NULL
)) {
147 udata
->debug
= fopen("audiodebug.raw", "ab");
148 DEBUGF("Audio debug file open\n");
152 Uint32 rd
= udata
->num_in
;
153 Uint32 wr
= (double)rd
* cvt
.len_ratio
;
155 if (wr
> udata
->num_out
) {
157 rd
= (double)wr
/ cvt
.len_ratio
;
159 if (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;
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
;
185 if (udata
->debug
!= NULL
) {
186 fwrite(cvt
.buf
, sizeof(Uint8
), cvt
.len_cvt
, udata
->debug
);
192 /* Convert is bad, so do silence */
193 Uint32 num
= wr
*obtained
.channels
;
197 switch (pcm_channel_bytes
)
201 Uint8
*stream
= udata
->stream
;
203 *stream
++ = obtained
.silence
;
208 Uint16
*stream
= (Uint16
*)udata
->stream
;
210 *stream
++ = obtained
.silence
;
215 if (udata
->debug
!= NULL
) {
216 fwrite(udata
->stream
, sizeof(Uint8
), wr
, udata
->debug
);
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
);
225 if (udata
->debug
!= NULL
) {
226 fwrite(pcm_data
, sizeof(Uint8
), udata
->num_out
* pcm_sample_bytes
,
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)
246 /* Audio card wants more? Get some more then. */
249 pcm_play_get_more_callback((void **)&pcm_data
, &pcm_data_size
);
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
;
264 pcm_play_dma_started_callback();
266 if ((size_t)len
> udata
->num_out
)
268 int delay
= pcm_data_size
*250 / pcm_sampr
- 1;
272 SDL_UnlockMutex(audio_lock
);
274 SDL_LockMutex(audio_lock
);
276 if (!pcm_is_playing())
282 pcm_data
+= udata
->num_in
;
283 pcm_data_size
-= udata
->num_in
;
284 udata
->stream
+= udata
->num_out
;
285 len
-= udata
->num_out
;
287 DEBUGF("sdl_audio_callback: No Data.\n");
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
)
325 void pcm_rec_dma_stop(void)
329 const void * pcm_rec_dma_get_peak_buffer(void)
334 void audiohw_set_recvol(int left
, int right
, int type
)
342 unsigned long spdif_measure_frequency(void)
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");
358 audio_lock
= SDL_CreateMutex();
362 panicf("Could not create audio_lock\n");
366 SDL_AudioSpec wanted_spec
;
370 udata
.debug
= fopen("audiodebug.raw", "wb");
371 DEBUGF("Audio debug file open\n");
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());
390 switch (obtained
.format
)
394 pcm_channel_bytes
= 1;
400 pcm_channel_bytes
= 2;
403 DEBUGF("Unknown sample format obtained: %u\n",
404 (unsigned)obtained
.format
);
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
)
422 #endif /* CONFIG_CODEC == SWCODEC */