blob: 5f061695a817958fc50233050d3a91be66d41755 [file] [log] [blame]
Daniel Stenberg0e419982006-01-09 11:22:36 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Nick Lanham
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Daniel Stenberg0e419982006-01-09 11:22:36 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "autoconf.h"
23
Daniel Stenberg0e419982006-01-09 11:22:36 +000024#include <stdlib.h>
Dan Everton3ba00602006-02-13 21:46:28 +000025#include <stdbool.h>
26#include <memory.h>
Jens Arnold4bd87152006-03-11 10:22:20 +000027#include "debug.h"
Dan Evertone3765452006-02-23 21:13:03 +000028#include "kernel.h"
Daniel Stenberg0e419982006-01-09 11:22:36 +000029#include "sound.h"
Michael Sevakisdfeeeeb2007-05-04 15:39:01 +000030
Michael Sevakis6077e5b2007-10-06 22:27:27 +000031#include "pcm.h"
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000032#include "pcm_sampr.h"
Dan Everton3ba00602006-02-13 21:46:28 +000033#include "SDL.h"
Daniel Stenberg0e419982006-01-09 11:22:36 +000034
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000035static int cvt_status = -1;
36static unsigned long pcm_frequency = SAMPR_44;
Daniel Stenberg0e419982006-01-09 11:22:36 +000037
Dan Everton3ba00602006-02-13 21:46:28 +000038static Uint8* pcm_data;
Thom Johansen738a5842006-03-22 16:04:01 +000039static size_t pcm_data_size;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000040static size_t pcm_sample_bytes;
41static size_t pcm_channel_bytes;
42
43struct pcm_udata
44{
45 Uint8 *stream;
46 Uint32 num_in;
47 Uint32 num_out;
48 FILE *debug;
49} udata;
Dan Everton3ba00602006-02-13 21:46:28 +000050
Dan Everton5efed092007-01-05 10:30:18 +000051static SDL_AudioSpec obtained;
52static SDL_AudioCVT cvt;
53
Dan Everton39452182006-02-21 21:48:06 +000054extern bool debug_audio;
55
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000056#ifndef MIN
57#define MIN(a, b) (((a) < (b)) ? (a) : (b))
58#endif
Daniel Stenberg0e419982006-01-09 11:22:36 +000059
Michael Sevakis6077e5b2007-10-06 22:27:27 +000060void pcm_play_lock(void)
61{
62 SDL_LockAudio();
63}
64
65void pcm_play_unlock(void)
66{
67 SDL_UnlockAudio();
68}
69
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000070static void pcm_apply_settings_nolock(void)
71{
72 cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_frequency,
73 obtained.format, obtained.channels, obtained.freq);
74
Michael Sevakis6077e5b2007-10-06 22:27:27 +000075 pcm_curr_sampr = pcm_frequency;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000076
77 if (cvt_status < 0) {
Michael Sevakis6077e5b2007-10-06 22:27:27 +000078 cvt.len_ratio = (double)obtained.freq / (double)pcm_curr_sampr;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000079 }
80}
81
82void pcm_apply_settings(void)
83{
Michael Sevakis6077e5b2007-10-06 22:27:27 +000084 pcm_play_lock();
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000085 pcm_apply_settings_nolock();
Michael Sevakis6077e5b2007-10-06 22:27:27 +000086 pcm_play_unlock();
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000087}
88
Michael Sevakis6077e5b2007-10-06 22:27:27 +000089void pcm_play_dma_start(const void *addr, size_t size)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000090{
Michael Sevakis2aaf45e2007-05-04 15:14:56 +000091 pcm_apply_settings_nolock();
92
Dan Everton3ba00602006-02-13 21:46:28 +000093 pcm_data = (Uint8 *) addr;
94 pcm_data_size = size;
Daniel Stenberg0e419982006-01-09 11:22:36 +000095
Dan Everton3ba00602006-02-13 21:46:28 +000096 SDL_PauseAudio(0);
Daniel Stenberg0e419982006-01-09 11:22:36 +000097}
98
Michael Sevakis6077e5b2007-10-06 22:27:27 +000099void pcm_play_dma_stop(void)
Daniel Stenberg0e419982006-01-09 11:22:36 +0000100{
Dan Everton3ba00602006-02-13 21:46:28 +0000101 SDL_PauseAudio(1);
Daniel Stenberg0e419982006-01-09 11:22:36 +0000102}
103
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000104void pcm_play_dma_pause(bool pause)
Daniel Stenberg0e419982006-01-09 11:22:36 +0000105{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000106 if (pause)
107 SDL_PauseAudio(1);
108 else
109 SDL_PauseAudio(0);
Dan Everton3ba00602006-02-13 21:46:28 +0000110}
111
112size_t pcm_get_bytes_waiting(void)
113{
114 return pcm_data_size;
115}
116
Dave Chapmanec529a12007-01-01 14:01:08 +0000117void pcm_set_frequency(unsigned int frequency)
118{
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000119 switch (frequency)
120 {
121 HW_HAVE_8_( case SAMPR_8:)
122 HW_HAVE_11_(case SAMPR_11:)
123 HW_HAVE_12_(case SAMPR_12:)
124 HW_HAVE_16_(case SAMPR_16:)
125 HW_HAVE_22_(case SAMPR_22:)
126 HW_HAVE_24_(case SAMPR_24:)
127 HW_HAVE_32_(case SAMPR_32:)
Michael Sevakisdfeeeeb2007-05-04 15:39:01 +0000128 HW_HAVE_44_(case SAMPR_44:)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000129 HW_HAVE_48_(case SAMPR_48:)
130 HW_HAVE_64_(case SAMPR_64:)
131 HW_HAVE_88_(case SAMPR_88:)
132 HW_HAVE_96_(case SAMPR_96:)
133 break;
134 default:
135 frequency = SAMPR_44;
136 }
137
138 pcm_frequency = frequency;
Dave Chapmanec529a12007-01-01 14:01:08 +0000139}
140
Jonathan Gordonfe142f12007-07-31 11:50:56 +0000141extern int sim_volume; /* in firmware/sound.c */
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000142void write_to_soundcard(struct pcm_udata *udata) {
Dan Everton5efed092007-01-05 10:30:18 +0000143 if (cvt.needed) {
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000144 Uint32 rd = udata->num_in;
145 Uint32 wr = (double)rd * cvt.len_ratio;
Dan Everton5efed092007-01-05 10:30:18 +0000146
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000147 if (wr > udata->num_out) {
148 wr = udata->num_out;
149 rd = (double)wr / cvt.len_ratio;
Dan Everton5efed092007-01-05 10:30:18 +0000150
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000151 if (rd > udata->num_in)
152 {
153 rd = udata->num_in;
154 wr = (double)rd * cvt.len_ratio;
155 }
Dan Everton5efed092007-01-05 10:30:18 +0000156 }
157
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000158 if (wr == 0 || rd == 0)
159 {
160 udata->num_out = udata->num_in = 0;
161 return;
162 }
163
164 if (cvt_status > 0) {
165 cvt.len = rd * pcm_sample_bytes;
166 cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
167
168 memcpy(cvt.buf, pcm_data, cvt.len);
169
170 SDL_ConvertAudio(&cvt);
Jonathan Gordon42e42222007-07-31 11:41:42 +0000171 SDL_MixAudio(udata->stream, cvt.buf, cvt.len_cvt, sim_volume);
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000172
173 udata->num_in = cvt.len / pcm_sample_bytes;
174 udata->num_out = cvt.len_cvt / pcm_sample_bytes;
175
176 if (udata->debug != NULL) {
177 fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
178 }
179
180 free(cvt.buf);
181 }
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;
187
188 switch (pcm_channel_bytes)
189 {
190 case 1:
191 {
192 Uint8 *stream = udata->stream;
193 while (num-- > 0)
194 *stream++ = obtained.silence;
195 break;
196 }
197 case 2:
198 {
199 Uint16 *stream = (Uint16 *)udata->stream;
200 while (num-- > 0)
201 *stream++ = obtained.silence;
202 break;
203 }
204 }
205
206 if (udata->debug != NULL) {
207 fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
208 }
209 }
Dan Everton5efed092007-01-05 10:30:18 +0000210 } else {
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000211 udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
Jonathan Gordon42e42222007-07-31 11:41:42 +0000212 SDL_MixAudio(udata->stream, pcm_data,
213 udata->num_out * pcm_sample_bytes, sim_volume);
Dan Everton5efed092007-01-05 10:30:18 +0000214
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000215 if (udata->debug != NULL) {
216 fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
217 udata->debug);
Dan Everton5efed092007-01-05 10:30:18 +0000218 }
219 }
Dan Everton5efed092007-01-05 10:30:18 +0000220}
221
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000222void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
Dan Everton3ba00602006-02-13 21:46:28 +0000223{
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000224 udata->stream = stream;
Dan Everton39452182006-02-21 21:48:06 +0000225
Dan Everton5efed092007-01-05 10:30:18 +0000226 /* Write what we have in the PCM buffer */
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000227 if (pcm_data_size > 0)
228 goto start;
Dan Everton4f54dbd2006-02-22 22:45:10 +0000229
Dan Everton5efed092007-01-05 10:30:18 +0000230 /* Audio card wants more? Get some more then. */
231 while (len > 0) {
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000232 if ((ssize_t)pcm_data_size <= 0) {
Jens Arnold4bd87152006-03-11 10:22:20 +0000233 pcm_data_size = 0;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000234
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000235 if (pcm_callback_for_more)
236 pcm_callback_for_more(&pcm_data, &pcm_data_size);
Dan Everton39452182006-02-21 21:48:06 +0000237 }
Dan Everton5efed092007-01-05 10:30:18 +0000238
Jens Arnold4bd87152006-03-11 10:22:20 +0000239 if (pcm_data_size > 0) {
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000240 start:
241 udata->num_in = pcm_data_size / pcm_sample_bytes;
242 udata->num_out = len / pcm_sample_bytes;
243
244 write_to_soundcard(udata);
245
246 udata->num_in *= pcm_sample_bytes;
247 udata->num_out *= pcm_sample_bytes;
248
249 pcm_data += udata->num_in;
250 pcm_data_size -= udata->num_in;
251 udata->stream += udata->num_out;
252 len -= udata->num_out;
Jens Arnold4bd87152006-03-11 10:22:20 +0000253 } else {
254 DEBUGF("sdl_audio_callback: No Data.\n");
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000255 pcm_play_dma_stop();
256 pcm_play_dma_stopped_callback();
Jens Arnold4bd87152006-03-11 10:22:20 +0000257 break;
258 }
Dan Everton4f54dbd2006-02-22 22:45:10 +0000259 }
Dan Everton3ba00602006-02-13 21:46:28 +0000260}
261
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000262const void * pcm_play_dma_get_peak_buffer(int *count)
263{
264 uintptr_t addr = (uintptr_t)pcm_data;
265 *count = pcm_data_size / 4;
266 return (void *)((addr + 2) & ~3);
267}
268
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000269#ifdef HAVE_RECORDING
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000270void pcm_rec_lock(void)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000271{
272}
273
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000274void pcm_rec_unlock(void)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000275{
276}
277
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000278void pcm_rec_dma_init(void)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000279{
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000280}
281
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000282void pcm_rec_dma_close(void)
283{
284}
285
286void pcm_rec_dma_start(void *start, size_t size)
287{
Michael Sevakis32f8c402007-10-07 06:13:05 +0000288 (void)start;
289 (void)size;
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000290}
291
292void pcm_rec_dma_stop(void)
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000293{
294}
295
296void pcm_record_more(void *start, size_t size)
297{
298 (void)start;
299 (void)size;
300}
301
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000302unsigned long pcm_rec_status(void)
303{
304 return 0;
305}
306
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000307const void * pcm_rec_dma_get_peak_buffer(int *count)
308{
309 *count = 0;
310 return NULL;
311}
312
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000313#endif /* HAVE_RECORDING */
314
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000315void pcm_play_dma_init(void)
Dan Everton3ba00602006-02-13 21:46:28 +0000316{
Dan Everton5efed092007-01-05 10:30:18 +0000317 SDL_AudioSpec wanted_spec;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000318 udata.debug = NULL;
Dan Everton39452182006-02-21 21:48:06 +0000319
320 if (debug_audio) {
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000321 udata.debug = fopen("audiodebug.raw", "wb");
Dan Everton39452182006-02-21 21:48:06 +0000322 }
Dan Everton3ba00602006-02-13 21:46:28 +0000323
324 /* Set 16-bit stereo audio at 44Khz */
Dan Everton5efed092007-01-05 10:30:18 +0000325 wanted_spec.freq = 44100;
326 wanted_spec.format = AUDIO_S16SYS;
327 wanted_spec.channels = 2;
328 wanted_spec.samples = 2048;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000329 wanted_spec.callback =
330 (void (SDLCALL *)(void *userdata,
331 Uint8 *stream, int len))sdl_audio_callback;
332 wanted_spec.userdata = &udata;
Dan Everton3ba00602006-02-13 21:46:28 +0000333
334 /* Open the audio device and start playing sound! */
Dan Everton5efed092007-01-05 10:30:18 +0000335 if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
Dan Everton3ba00602006-02-13 21:46:28 +0000336 fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000337 return;
Dan Everton3ba00602006-02-13 21:46:28 +0000338 }
Dan Everton39452182006-02-21 21:48:06 +0000339
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000340 switch (obtained.format)
341 {
342 case AUDIO_U8:
343 case AUDIO_S8:
344 pcm_channel_bytes = 1;
345 break;
346 case AUDIO_U16LSB:
347 case AUDIO_S16LSB:
348 case AUDIO_U16MSB:
349 case AUDIO_S16MSB:
350 pcm_channel_bytes = 2;
351 break;
352 default:
353 fprintf(stderr, "Unknown sample format obtained: %u\n",
354 (unsigned)obtained.format);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000355 return;
Michael Sevakis2aaf45e2007-05-04 15:14:56 +0000356 }
357
358 pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
359
360 pcm_apply_settings_nolock();
Daniel Stenberg0e419982006-01-09 11:22:36 +0000361}
362
Michael Sevakisc2d21062007-03-11 06:21:43 +0000363void pcm_postinit(void)
364{
365}