1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Nick Lanham
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
30 #include "pcm_sampr.h"
33 static int cvt_status
= -1;
34 static unsigned long pcm_frequency
= SAMPR_44
;
36 static Uint8
* pcm_data
;
37 static size_t pcm_data_size
;
38 static size_t pcm_sample_bytes
;
39 static size_t pcm_channel_bytes
;
49 static SDL_AudioSpec obtained
;
50 static SDL_AudioCVT cvt
;
52 extern bool debug_audio
;
55 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
58 void pcm_play_lock(void)
63 void pcm_play_unlock(void)
68 static void pcm_apply_settings_nolock(void)
70 cvt_status
= SDL_BuildAudioCVT(&cvt
, AUDIO_S16SYS
, 2, pcm_frequency
,
71 obtained
.format
, obtained
.channels
, obtained
.freq
);
73 pcm_curr_sampr
= pcm_frequency
;
76 cvt
.len_ratio
= (double)obtained
.freq
/ (double)pcm_curr_sampr
;
80 void pcm_apply_settings(void)
83 pcm_apply_settings_nolock();
87 void pcm_play_dma_start(const void *addr
, size_t size
)
89 pcm_apply_settings_nolock();
91 pcm_data
= (Uint8
*) addr
;
97 void pcm_play_dma_stop(void)
102 void pcm_play_dma_pause(bool pause
)
110 size_t pcm_get_bytes_waiting(void)
112 return pcm_data_size
;
115 void pcm_set_frequency(unsigned int frequency
)
119 HW_HAVE_8_( case SAMPR_8
:)
120 HW_HAVE_11_(case SAMPR_11
:)
121 HW_HAVE_12_(case SAMPR_12
:)
122 HW_HAVE_16_(case SAMPR_16
:)
123 HW_HAVE_22_(case SAMPR_22
:)
124 HW_HAVE_24_(case SAMPR_24
:)
125 HW_HAVE_32_(case SAMPR_32
:)
126 HW_HAVE_44_(case SAMPR_44
:)
127 HW_HAVE_48_(case SAMPR_48
:)
128 HW_HAVE_64_(case SAMPR_64
:)
129 HW_HAVE_88_(case SAMPR_88
:)
130 HW_HAVE_96_(case SAMPR_96
:)
133 frequency
= SAMPR_44
;
136 pcm_frequency
= frequency
;
139 extern int sim_volume
; /* in firmware/sound.c */
140 void write_to_soundcard(struct pcm_udata
*udata
) {
142 Uint32 rd
= udata
->num_in
;
143 Uint32 wr
= (double)rd
* cvt
.len_ratio
;
145 if (wr
> udata
->num_out
) {
147 rd
= (double)wr
/ cvt
.len_ratio
;
149 if (rd
> udata
->num_in
)
152 wr
= (double)rd
* cvt
.len_ratio
;
156 if (wr
== 0 || rd
== 0)
158 udata
->num_out
= udata
->num_in
= 0;
162 if (cvt_status
> 0) {
163 cvt
.len
= rd
* pcm_sample_bytes
;
164 cvt
.buf
= (Uint8
*) malloc(cvt
.len
* cvt
.len_mult
);
166 memcpy(cvt
.buf
, pcm_data
, cvt
.len
);
168 SDL_ConvertAudio(&cvt
);
169 SDL_MixAudio(udata
->stream
, cvt
.buf
, cvt
.len_cvt
, sim_volume
);
171 udata
->num_in
= cvt
.len
/ pcm_sample_bytes
;
172 udata
->num_out
= cvt
.len_cvt
/ pcm_sample_bytes
;
174 if (udata
->debug
!= NULL
) {
175 fwrite(cvt
.buf
, sizeof(Uint8
), cvt
.len_cvt
, udata
->debug
);
181 /* Convert is bad, so do silence */
182 Uint32 num
= wr
*obtained
.channels
;
186 switch (pcm_channel_bytes
)
190 Uint8
*stream
= udata
->stream
;
192 *stream
++ = obtained
.silence
;
197 Uint16
*stream
= (Uint16
*)udata
->stream
;
199 *stream
++ = obtained
.silence
;
204 if (udata
->debug
!= NULL
) {
205 fwrite(udata
->stream
, sizeof(Uint8
), wr
, udata
->debug
);
209 udata
->num_in
= udata
->num_out
= MIN(udata
->num_in
, udata
->num_out
);
210 SDL_MixAudio(udata
->stream
, pcm_data
,
211 udata
->num_out
* pcm_sample_bytes
, sim_volume
);
213 if (udata
->debug
!= NULL
) {
214 fwrite(pcm_data
, sizeof(Uint8
), udata
->num_out
* pcm_sample_bytes
,
220 void sdl_audio_callback(struct pcm_udata
*udata
, Uint8
*stream
, int len
)
222 udata
->stream
= stream
;
224 /* Write what we have in the PCM buffer */
225 if (pcm_data_size
> 0)
228 /* Audio card wants more? Get some more then. */
230 if ((ssize_t
)pcm_data_size
<= 0) {
233 if (pcm_callback_for_more
)
234 pcm_callback_for_more(&pcm_data
, &pcm_data_size
);
237 if (pcm_data_size
> 0) {
239 udata
->num_in
= pcm_data_size
/ pcm_sample_bytes
;
240 udata
->num_out
= len
/ pcm_sample_bytes
;
242 write_to_soundcard(udata
);
244 udata
->num_in
*= pcm_sample_bytes
;
245 udata
->num_out
*= pcm_sample_bytes
;
247 pcm_data
+= udata
->num_in
;
248 pcm_data_size
-= udata
->num_in
;
249 udata
->stream
+= udata
->num_out
;
250 len
-= udata
->num_out
;
252 DEBUGF("sdl_audio_callback: No Data.\n");
254 pcm_play_dma_stopped_callback();
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
)
290 void pcm_rec_dma_stop(void)
294 void pcm_record_more(void *start
, size_t size
)
300 unsigned long pcm_rec_status(void)
305 const void * pcm_rec_dma_get_peak_buffer(int *count
)
311 #endif /* HAVE_RECORDING */
313 void pcm_play_dma_init(void)
315 SDL_AudioSpec wanted_spec
;
319 udata
.debug
= fopen("audiodebug.raw", "wb");
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 fprintf(stderr
, "Unable to open audio: %s\n", SDL_GetError());
338 switch (obtained
.format
)
342 pcm_channel_bytes
= 1;
348 pcm_channel_bytes
= 2;
351 fprintf(stderr
, "Unknown sample format obtained: %u\n",
352 (unsigned)obtained
.format
);
356 pcm_sample_bytes
= obtained
.channels
* pcm_channel_bytes
;
358 pcm_apply_settings_nolock();
361 void pcm_postinit(void)