Commit 0089ba6c authored by Ryan C. Gordon's avatar Ryan C. Gordon

Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%402195
parent c500a063
......@@ -511,9 +511,17 @@ CheckNAS()
AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
, enable_nas=yes)
if test x$enable_audio = xyes -a x$enable_nas = xyes; then
AC_CHECK_HEADER(audio/audiolib.h, have_nas_hdr=yes)
AC_CHECK_LIB(audio, AuOpenServer, have_nas_lib=yes)
AC_MSG_CHECKING(for NAS audio support)
have_nas=no
if test -r /usr/X11R6/include/audio/audiolib.h; then
if test x$have_nas_hdr = xyes -a x$have_nas_lib = xyes; then
have_nas=yes
NAS_LIBS="-laudio"
elif test -r /usr/X11R6/include/audio/audiolib.h; then
have_nas=yes
NAS_CFLAGS="-I/usr/X11R6/include/"
NAS_LIBS="-L/usr/X11R6/lib -laudio -lXt"
......@@ -525,12 +533,40 @@ AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
have_nas=yes
NAS_LIBS="-lnas -lXt"
fi
AC_MSG_RESULT($have_nas)
if test x$have_nas = xyes; then
AC_ARG_ENABLE(nas-shared,
AC_HELP_STRING([--enable-nas-shared], [dynamically load NAS audio support [[default=yes]]]),
, enable_nas_shared=yes)
if test "x`echo $NAS_LIBS | grep -- -L`" = "x"; then
if test "x`ls /lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/lib $NAS_LIBS"
elif test "x`ls /usr/lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/usr/lib $NAS_LIBS"
elif test "x`ls /usr/local/lib/libaudio.so.* 2> /dev/null`" != "x"; then
NAS_LIBS="-L/usr/local/lib $NAS_LIBS"
fi
fi
nas_lib_spec=`echo $NAS_LIBS | sed 's/.*-L\([[^ ]]*\).*/\1\/libaudio.so.*/'`
nas_lib=`ls -- $nas_lib_spec | sed 's/.*\/\(.*\)/\1/; q'`
echo "-- $nas_lib_spec -> $nas_lib"
if test x$have_loadso != xyes && \
test x$enable_nas_shared = xyes; then
AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic NAS loading])
fi
if test x$have_loadso = xyes && \
test x$enable_nas_shared = xyes && test x$alsa_lib != x; then
AC_DEFINE_UNQUOTED(SDL_AUDIO_DRIVER_NAS_DYNAMIC, "$nas_lib")
else
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
fi
AC_DEFINE(SDL_AUDIO_DRIVER_NAS)
SOURCES="$SOURCES $srcdir/src/audio/nas/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
have_audio=yes
fi
fi
......@@ -2006,7 +2042,7 @@ case "$host" in
have_audio=yes
;;
aix)
AC_DEFINE(SDL_AUDIO_DRIVER_PAUD)
AC_DEFINE(SDL_AUDIO_DRIVER_PAUDIO)
SOURCES="$SOURCES $srcdir/src/audio/paudio/*.c"
have_audio=yes
;;
......@@ -2206,7 +2242,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
CheckBeGL
# Set up files for the audio library
if test x$enable_audio = xyes; then
AC_DEFINE(SDL_AUDIO_DRIVER_BAUDIO)
AC_DEFINE(SDL_AUDIO_DRIVER_BEOSAUDIO)
SOURCES="$SOURCES $srcdir/src/audio/baudio/*.cc"
have_audio=yes
fi
......@@ -2323,7 +2359,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
# If either the audio or CD driver is used, add the AudioUnit framework
if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -framework,AudioToolbox -Wl,-framework,AudioUnit"
fi
;;
*-*-mint*)
......
......@@ -153,7 +153,7 @@ typedef struct SDL_AudioCVT
/* Function prototypes */
/* These functions return the list of built in video drivers, in the
/* These functions return the list of built in audio drivers, in the
* order that they are normally initialized by default.
*/
extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
......@@ -212,7 +212,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
* may modify the requested size of the audio buffer, you should allocate
* any local mixing buffers after you open the audio device.
*/
extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
extern DECLSPEC int SDLCALL SDL_OpenAudio(const SDL_AudioSpec * desired,
SDL_AudioSpec * obtained);
/*
......@@ -228,6 +228,13 @@ typedef Uint32 SDL_AudioDeviceID;
/*
* Get the number of available devices exposed by the current driver.
* Only valid after a successfully initializing the audio subsystem.
* Returns -1 if an explicit list of devices can't be determined; this is
* not an error. For example, if SDL is set up to talk to a remote audio
* server, it can't list every one available on the Internet, but it will
* still allow a specific host to be specified to SDL_OpenAudioDevice().
* In many common cases, when this function returns a value <= 0, it can still
* successfully open the default device (NULL for first argument of
* SDL_OpenAudioDevice()).
*/
extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
......@@ -235,15 +242,28 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
* Get the human-readable name of a specific audio device.
* Must be a value between 0 and (number of audio devices-1).
* Only valid after a successfully initializing the audio subsystem.
* The values returned by this function reflect the latest call to
* SDL_GetNumAudioDevices(); recall that function to redetect available
* hardware.
*
* The string returned by this function is UTF-8 encoded, read-only, and
* managed internally. You are not to free it. If you need to keep the
* string for any length of time, you should make your own copy of it, as it
* will be invalid next time any of several other SDL functions is called.
*/
extern DECLSPEC const char *SDLCALL SDL_GetAudioDevice(int index,
int iscapture);
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
int iscapture);
/*
* Open a specific audio device. Passing in a device name of NULL is
* equivalent to SDL_OpenAudio(). Returns 0 on error, a valid device ID
* on success.
* Open a specific audio device. Passing in a device name of NULL requests
* the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
* The device name is a UTF-8 string reported by SDL_GetAudioDevice(), but
* some drivers allow arbitrary and driver-specific strings, such as a
* hostname/IP address for a remote audio server, or a filename in the
* diskaudio driver.
* Returns 0 on error, a valid device ID that is >= 2 on success.
* SDL_OpenAudio(), unlike this function, always acts on device ID 1.
*/
extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
*device,
......
......@@ -154,7 +154,7 @@
#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#undef SDL_AUDIO_DRIVER_ARTS
#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
#undef SDL_AUDIO_DRIVER_BAUDIO
#undef SDL_AUDIO_DRIVER_BEOSAUDIO
#undef SDL_AUDIO_DRIVER_BSD
#undef SDL_AUDIO_DRIVER_COREAUDIO
#undef SDL_AUDIO_DRIVER_DART
......@@ -168,9 +168,10 @@
#undef SDL_AUDIO_DRIVER_MINT
#undef SDL_AUDIO_DRIVER_MMEAUDIO
#undef SDL_AUDIO_DRIVER_NAS
#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
#undef SDL_AUDIO_DRIVER_OSS
#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
#undef SDL_AUDIO_DRIVER_PAUD
#undef SDL_AUDIO_DRIVER_PAUDIO
#undef SDL_AUDIO_DRIVER_QNXNTO
#undef SDL_AUDIO_DRIVER_SNDMGR
#undef SDL_AUDIO_DRIVER_SUNAUDIO
......
......@@ -91,7 +91,7 @@ typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
#endif
extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (*fn) (void *),
extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (SDLCALL * f) (void *),
void *data,
pfnSDL_CurrentBeginThread
pfnBeginThread,
......
......@@ -28,6 +28,7 @@
/* Routine to get the thread-specific error variable */
#if SDL_THREADS_DISABLED
/* !!! FIXME: what does this comment mean? Victim of Search and Replace? */
/* The SDL_arraysize(The ),default (non-thread-safe) global error variable */
static SDL_error SDL_global_error;
#define SDL_GetErrBuf() (&SDL_global_error)
......
......@@ -28,11 +28,48 @@
#include "SDL_audiomem.h"
#include "SDL_sysaudio.h"
#ifdef __OS2__
/* We'll need the DosSetPriority() API! */
#define INCL_DOSPROCESS
#include <os2.h>
#endif
#define _THIS SDL_AudioDevice *this
static SDL_AudioDriver current_audio;
static SDL_AudioDevice *open_devices[16];
/* !!! FIXME: These are wordy and unlocalized... */
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
/*
* Not all of these will be compiled and linked in, but it's convenient
* to have a complete list here and saves yet-another block of #ifdefs...
* Please see bootstrap[], below, for the actual #ifdef mess.
*/
extern AudioBootStrap BSD_AUDIO_bootstrap;
extern AudioBootStrap DSP_bootstrap;
extern AudioBootStrap DMA_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
extern AudioBootStrap QNXNTOAUDIO_bootstrap;
extern AudioBootStrap SUNAUDIO_bootstrap;
extern AudioBootStrap DMEDIA_bootstrap;
extern AudioBootStrap ARTS_bootstrap;
extern AudioBootStrap ESD_bootstrap;
extern AudioBootStrap NAS_bootstrap;
extern AudioBootStrap DSOUND_bootstrap;
extern AudioBootStrap WAVEOUT_bootstrap;
extern AudioBootStrap PAUDIO_bootstrap;
extern AudioBootStrap BEOSAUDIO_bootstrap;
extern AudioBootStrap COREAUDIO_bootstrap;
extern AudioBootStrap SNDMGR_bootstrap;
extern AudioBootStrap MINTAUDIO_GSXB_bootstrap;
extern AudioBootStrap MINTAUDIO_MCSN_bootstrap;
extern AudioBootStrap MINTAUDIO_STFA_bootstrap;
extern AudioBootStrap MINTAUDIO_XBIOS_bootstrap;
extern AudioBootStrap MINTAUDIO_DMA8_bootstrap;
extern AudioBootStrap DISKAUD_bootstrap;
extern AudioBootStrap DUMMYAUD_bootstrap;
extern AudioBootStrap DCAUD_bootstrap;
extern AudioBootStrap MMEAUDIO_bootstrap;
extern AudioBootStrap DART_bootstrap;
/* Available audio drivers */
static AudioBootStrap *bootstrap[] = {
......@@ -70,11 +107,11 @@ static AudioBootStrap *bootstrap[] = {
#if SDL_AUDIO_DRIVER_WAVEOUT
&WAVEOUT_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_PAUD
&Paud_bootstrap,
#if SDL_AUDIO_DRIVER_PAUDIO
&PAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_BAUDIO
&BAUDIO_bootstrap,
#if SDL_AUDIO_DRIVER_BEOSAUDIO
&BEOSAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_COREAUDIO
&COREAUDIO_bootstrap,
......@@ -82,9 +119,6 @@ static AudioBootStrap *bootstrap[] = {
#if SDL_AUDIO_DRIVER_SNDMGR
&SNDMGR_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_AHI
&AHI_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_MINT
&MINTAUDIO_GSXB_bootstrap,
&MINTAUDIO_MCSN_bootstrap,
......@@ -109,227 +143,201 @@ static AudioBootStrap *bootstrap[] = {
#endif
NULL
};
SDL_AudioDevice *current_audio = NULL;
/* Various local functions */
int SDL_AudioInit(const char *driver_name);
void SDL_AudioQuit(void);
static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
{
id--;
if ( (id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL) ) {
SDL_SetError("Invalid audio device ID");
return NULL;
}
return open_devices[id];
}
/* stubs for audio drivers that don't need a specific entry point... */
static int SDL_AudioDetectDevices_Default(int iscapture) { return -1; }
static void SDL_AudioThreadInit_Default(_THIS) { /* no-op. */ }
static void SDL_AudioWaitDevice_Default(_THIS) { /* no-op. */ }
static void SDL_AudioPlayDevice_Default(_THIS) { /* no-op. */ }
static Uint8 *SDL_AudioGetDeviceBuf_Default(_THIS) { return NULL; }
static void SDL_AudioWaitDone_Default(_THIS) { /* no-op. */ }
static void SDL_AudioCloseDevice_Default(_THIS) { /* no-op. */ }
static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ }
static int
SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture)
{
return 0;
}
static const char *SDL_AudioGetDeviceName_Default(int index, int iscapture)
{
SDL_SetError("No such device");
return NULL;
}
static void
SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
{
if (device->thread && (SDL_ThreadID() == device->threadid)) {
return;
}
SDL_mutexP(device->mixer_lock);
}
static void
SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
{
if (device->thread && (SDL_ThreadID() == device->threadid)) {
return;
}
SDL_mutexV(device->mixer_lock);
}
static void finalize_audio_entry_points(void)
{
/*
* Fill in stub functions for unused driver entry points. This lets us
* blindly call them without having to check for validity first.
*/
#define FILL_STUB(x) \
if (current_audio.impl.x == NULL) { \
current_audio.impl.x = SDL_Audio##x##_Default; \
}
FILL_STUB(DetectDevices);
FILL_STUB(GetDeviceName);
FILL_STUB(OpenDevice);
FILL_STUB(ThreadInit);
FILL_STUB(WaitDevice);
FILL_STUB(PlayDevice);
FILL_STUB(GetDeviceBuf);
FILL_STUB(WaitDone);
FILL_STUB(CloseDevice);
FILL_STUB(LockDevice);
FILL_STUB(UnlockDevice);
FILL_STUB(Deinitialize);
#undef FILL_STUB
}
#if SDL_AUDIO_DRIVER_AHI
static int audio_configured = 0;
#endif
/* The general mixing thread function */
int SDLCALL
SDL_RunAudio(void *audiop)
SDL_RunAudio(void *devicep)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) audiop;
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
const int legacy_device = (device == open_devices[0]);
Uint8 *stream;
int stream_len;
void *udata;
void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
int silence;
#if SDL_AUDIO_DRIVER_AHI
int started = 0;
/* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
D(bug("Task audio started audio struct:<%lx>...\n", audiop));
D(bug("Before Openaudio..."));
if (audio->OpenAudio(audio, &audio->spec) == -1) {
D(bug("Open audio failed...\n"));
return (-1);
}
D(bug("OpenAudio...OK\n"));
#endif
/* Perform any thread setup */
if (audio->ThreadInit) {
audio->ThreadInit(audio);
}
audio->threadid = SDL_ThreadID();
device->threadid = SDL_ThreadID();
current_audio.impl.ThreadInit(device);
/* Set up the mixing function */
fill = audio->spec.callback;
udata = audio->spec.userdata;
#if SDL_AUDIO_DRIVER_AHI
audio_configured = 1;
fill = device->spec.callback;
udata = device->spec.userdata;
D(bug("Audio configured... Checking for conversion\n"));
SDL_mutexP(audio->mixer_lock);
D(bug("Semaphore obtained...\n"));
#endif
if (audio->convert.needed) {
if (audio->convert.src_format == AUDIO_U8) {
if (device->convert.needed) {
if (device->convert.src_format == AUDIO_U8) {
silence = 0x80;
} else {
silence = 0;
}
stream_len = audio->convert.len;
stream_len = device->convert.len;
} else {
silence = audio->spec.silence;
stream_len = audio->spec.size;
silence = device->spec.silence;
stream_len = device->spec.size;
}
#if SDL_AUDIO_DRIVER_AHI
SDL_mutexV(audio->mixer_lock);
D(bug("Entering audio loop...\n"));
#endif
#ifdef __OS2__
/* Increase the priority of this thread to make sure that
the audio will be continuous all the time! */
#ifdef USE_DOSSETPRIORITY
if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) {
#ifdef DEBUG_BUILD
printf
("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n",
SDL_ThreadID());
#endif
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
} else {
#ifdef DEBUG_BUILD
printf
("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n",
SDL_ThreadID());
#endif
DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
}
#endif
#endif
/* Loop, filling the audio buffers */
while (audio->enabled) {
while (device->enabled) {
/* Fill the current buffer with sound */
if (audio->convert.needed) {
if (audio->convert.buf) {
stream = audio->convert.buf;
if (device->convert.needed) {
if (device->convert.buf) {
stream = device->convert.buf;
} else {
continue;
}
} else {
stream = audio->GetAudioBuf(audio);
stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) {
stream = audio->fake_stream;
stream = device->fake_stream;
}
}
SDL_memset(stream, silence, stream_len);
if (!audio->paused) {
SDL_mutexP(audio->mixer_lock);
/* New code should fill buffer or set it to silence themselves. */
if (legacy_device) {
SDL_memset(stream, silence, stream_len);
}
if (!device->paused) {
SDL_mutexP(device->mixer_lock);
(*fill) (udata, stream, stream_len);
SDL_mutexV(audio->mixer_lock);
SDL_mutexV(device->mixer_lock);
}
/* Convert the audio if necessary */
if (audio->convert.needed) {
SDL_ConvertAudio(&audio->convert);
stream = audio->GetAudioBuf(audio);
if (device->convert.needed) {
SDL_ConvertAudio(&device->convert);
stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) {
stream = audio->fake_stream;
stream = device->fake_stream;
}
SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt);
}
/* Ready current buffer for play and change current buffer */
if (stream != audio->fake_stream) {
audio->PlayAudio(audio);
if (stream != device->fake_stream) {
current_audio.impl.PlayDevice(device);
}
/* Wait for an audio buffer to become available */
if (stream == audio->fake_stream) {
SDL_Delay((audio->spec.samples * 1000) / audio->spec.freq);
if (stream == device->fake_stream) {
SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
} else {
audio->WaitAudio(audio);
current_audio.impl.WaitDevice(device);
}
}
/* Wait for the audio to drain.. */
if (audio->WaitDone) {
audio->WaitDone(audio);
}
#if SDL_AUDIO_DRIVER_AHI
D(bug("WaitAudio...Done\n"));
current_audio.impl.WaitDone(device);
audio->CloseAudio(audio);
D(bug("CloseAudio..Done, subtask exiting...\n"));
audio_configured = 0;
#endif
#ifdef __OS2__
#ifdef DEBUG_BUILD
printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
#endif
#endif
return (0);
}
static void
SDL_LockAudio_Default(SDL_AudioDevice * audio)
{
if (audio->thread && (SDL_ThreadID() == audio->threadid)) {
return;
}
SDL_mutexP(audio->mixer_lock);
}
static void
SDL_UnlockAudio_Default(SDL_AudioDevice * audio)
{
if (audio->thread && (SDL_ThreadID() == audio->threadid)) {
return;
}
SDL_mutexV(audio->mixer_lock);
}
static SDL_AudioFormat
SDL_ParseAudioFormat(const char *string)
{
SDL_AudioFormat format = 0;
switch (*string) {
case 'U':
++string;
format |= 0x0000;
break;
case 'S':
++string;
format |= 0x8000;
break;
default:
return 0;
}
switch (SDL_atoi(string)) {
case 8:
string += 1;
format |= 8;
break;
case 16:
string += 2;
format |= 16;
if (SDL_strcmp(string, "LSB") == 0
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|| SDL_strcmp(string, "SYS") == 0
#endif
) {
format |= 0x0000;
}
if (SDL_strcmp(string, "MSB") == 0
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|| SDL_strcmp(string, "SYS") == 0
#endif
) {
format |= 0x1000;
}
break;
default:
return 0;
}
return format;
#define CHECK_FMT_STRING(x) if (strcmp(string, #x) == 0) return AUDIO_##x
CHECK_FMT_STRING(U8);
CHECK_FMT_STRING(S8);
CHECK_FMT_STRING(U16LSB);
CHECK_FMT_STRING(S16LSB);
CHECK_FMT_STRING(U16MSB);
CHECK_FMT_STRING(S16MSB);
CHECK_FMT_STRING(U16SYS);
CHECK_FMT_STRING(S16SYS);
CHECK_FMT_STRING(U16);
CHECK_FMT_STRING(S16);
CHECK_FMT_STRING(S32LSB);
CHECK_FMT_STRING(S32MSB);
CHECK_FMT_STRING(S32SYS);
CHECK_FMT_STRING(S32);
CHECK_FMT_STRING(F32LSB);
CHECK_FMT_STRING(F32MSB);
CHECK_FMT_STRING(F32SYS);
CHECK_FMT_STRING(F32);
#undef CHECK_FMT_STRING
return 0;
}
int
......@@ -350,92 +358,53 @@ SDL_GetAudioDriver(int index)
int
SDL_AudioInit(const char *driver_name)
{
SDL_AudioDevice *audio;
int i = 0, idx;
int i = 0;
int initialized = 0;
int tried_to_init = 0;
/* Check to make sure we don't overwrite 'current_audio' */
if (current_audio != NULL) {
SDL_AudioQuit();
if (SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_AudioQuit(); /* shutdown driver if already running. */
}
SDL_memset(&current_audio, '\0', sizeof (current_audio));
SDL_memset(open_devices, '\0', sizeof (open_devices));
/* Select the proper audio driver */
audio = NULL;
idx = 0;
if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_AUDIODRIVER");
}
#if SDL_AUDIO_DRIVER_ESD
if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) {
/* Ahem, we know that if ESPEAKER is set, user probably wants
to use ESD, but don't start it if it's not already running.
This probably isn't the place to do this, but... Shh! :)
*/
for (i = 0; bootstrap[i]; ++i) {
if (SDL_strcasecmp(bootstrap[i]->name, "esd") == 0) {
#ifdef HAVE_PUTENV
const char *esd_no_spawn;
/* Don't start ESD if it's not running */
esd_no_spawn = getenv("ESD_NO_SPAWN");
if (esd_no_spawn == NULL) {
putenv("ESD_NO_SPAWN=1");
}
#endif
if (bootstrap[i]->available()) {
audio = bootstrap[i]->create(0);
break;
}
#ifdef HAVE_UNSETENV
if (esd_no_spawn == NULL) {
unsetenv("ESD_NO_SPAWN");
}
#endif
}
for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
/* make sure we should even try this driver before doing so... */
const AudioBootStrap *backend = bootstrap[i];
if ( ((driver_name) && (SDL_strcasecmp(backend->name, driver_name))) ||
((!driver_name) && (backend->demand_only)) ) {
continue;
}
tried_to_init = 1;
SDL_memset(&current_audio, 0, sizeof (current_audio));
current_audio.name = backend->name;
current_audio.desc = backend->desc;
initialized = backend->init(&current_audio.impl);
}
#endif /* SDL_AUDIO_DRIVER_ESD */
if (audio == NULL) {
if (driver_name != NULL) {
for (i = 0; bootstrap[i]; ++i) {
if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
if (bootstrap[i]->available()) {
audio = bootstrap[i]->create(idx);
}
break;
}
}
} else {
for (i = 0; bootstrap[i]; ++i) {
if (bootstrap[i]->available()) {
audio = bootstrap[i]->create(idx);
if (audio != NULL) {
break;
}
}
}
}
if (audio == NULL) {
if (!initialized) {
/* specific drivers will set the error message if they fail... */
if (!tried_to_init) {
if (driver_name) {
SDL_SetError("%s not available", driver_name);
} else {
SDL_SetError("No available audio device");
}
#if 0
/* Don't fail SDL_Init() if audio isn't available.
SDL_OpenAudio() will handle it at that point. *sigh*
*/
return (-1);
#endif
}
}
current_audio = audio;
if (current_audio) {
current_audio->name = bootstrap[i]->name;
if (!current_audio->LockAudio && !current_audio->UnlockAudio) {
current_audio->LockAudio = SDL_LockAudio_Default;
current_audio->UnlockAudio = SDL_UnlockAudio_Default;
}
SDL_memset(&current_audio, 0, sizeof (current_audio));
return (-1); /* No driver was available, so fail. */
}
finalize_audio_entry_points();
return (0);
}
......@@ -445,222 +414,369 @@ SDL_AudioInit(const char *driver_name)
const char *
SDL_GetCurrentAudioDriver()
{
if (current_audio) {
return current_audio->name;
}
return (NULL);
return current_audio.name;
}
int
SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
SDL_GetNumAudioDevices(int iscapture)
{
SDL_AudioDevice *audio;
const char *env;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
return -1;
}
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
return 0;
}
/* Start up the audio driver, if necessary */
if (!current_audio) {
if ((SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
(current_audio == NULL)) {
return (-1);
}
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
return 1;
}
audio = current_audio;
if (audio->opened) {
SDL_SetError("Audio device is already opened");
return (-1);
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
return 1;
}
/* Verify some parameters */
if (desired->freq == 0) {
env = SDL_getenv("SDL_AUDIO_FREQUENCY");
if (env) {
desired->freq = SDL_atoi(env);
}
return current_audio.impl.DetectDevices(iscapture);
}
const char *
SDL_GetAudioDeviceName(int index, int iscapture)
{
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_SetError("Audio subsystem is not initialized");
return NULL;
}
if (desired->freq == 0) {
/* Pick some default audio frequency */
desired->freq = 22050;
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
SDL_SetError("No capture support");
return NULL;
}
if (desired->format == 0) {
env = SDL_getenv("SDL_AUDIO_FORMAT");
if (env) {
desired->format = SDL_ParseAudioFormat(env);
}
if (index < 0) {
SDL_SetError("No such device");
return NULL;
}
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
return DEFAULT_INPUT_DEVNAME;
}
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
return DEFAULT_OUTPUT_DEVNAME;
}
return current_audio.impl.GetDeviceName(index, iscapture);
}
static void
close_audio_device(SDL_AudioDevice *device)
{
device->enabled = 0;
if (device->thread != NULL) {
SDL_WaitThread(device->thread, NULL);
}
if (device->mixer_lock != NULL) {
SDL_DestroyMutex(device->mixer_lock);
}
if (desired->format == 0) {
/* Pick some default audio format */
desired->format = AUDIO_S16;
if (device->fake_stream != NULL) {
SDL_FreeAudioMem(device->fake_stream);
}
if (desired->channels == 0) {
env = SDL_getenv("SDL_AUDIO_CHANNELS");
if (env) {
desired->channels = (Uint8) SDL_atoi(env);
if (device->convert.needed) {
SDL_FreeAudioMem(device->convert.buf);
}
if (device->opened) {
current_audio.impl.CloseDevice(device);
device->opened = 0;
}
SDL_FreeAudioMem(device);
}
/*
* Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
* Fills in a sanitized copy in (prepared).
* Returns non-zero if okay, zero on fatal parameters in (orig).
*/
static int
prepare_audiospec(const SDL_AudioSpec *orig, SDL_AudioSpec *prepared)
{
SDL_memcpy(prepared, orig, sizeof (SDL_AudioSpec));
if (orig->callback == NULL) {
SDL_SetError("SDL_OpenAudio() passed a NULL callback");
return 0;
}
if (orig->freq == 0) {
const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
if ( (!env) || ((prepared->freq = SDL_atoi(env)) == 0) ) {
prepared->freq = 22050; /* a reasonable default */
}
}
if (desired->channels == 0) {
/* Pick a default number of channels */
desired->channels = 2;
if (orig->format == 0) {
const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
prepared->format = AUDIO_S16; /* a reasonable default */
}
}
switch (orig->channels) {
case 0: {
const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
if ( (!env) || ((prepared->channels = SDL_atoi(env)) == 0) ) {
prepared->channels = 2; /* a reasonable default */
}
break;
}
switch (desired->channels) {
case 1: /* Mono */
case 2: /* Stereo */
case 4: /* surround */
case 6: /* surround with center and lfe */
break;
default:
SDL_SetError("1 (mono) and 2 (stereo) channels supported");
return (-1);
}
if (desired->samples == 0) {
env = SDL_getenv("SDL_AUDIO_SAMPLES");
if (env) {
desired->samples = (Uint16) SDL_atoi(env);
}
SDL_SetError("Unsupported number of audio channels.");
return 0;
}
if (desired->samples == 0) {
/* Pick a default of ~46 ms at desired frequency */
int samples = (desired->freq / 1000) * 46;
int power2 = 1;
while (power2 < samples) {
power2 *= 2;
if (orig->samples == 0) {
const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
if ( (!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0) ) {
/* Pick a default of ~46 ms at desired frequency */
/* !!! FIXME: remove this when the non-Po2 resampling is in. */
const int samples = (prepared->freq / 1000) * 46;
int power2 = 1;
while (power2 < samples) {
power2 *= 2;
}
prepared->samples = power2;
}
desired->samples = power2;
}
if (desired->callback == NULL) {
SDL_SetError("SDL_OpenAudio() passed a NULL callback");
return (-1);
/* Calculate the silence and size of the audio specification */
SDL_CalculateAudioSpec(prepared);
return 1;
}
static SDL_AudioDeviceID
open_audio_device(const char *devname, int iscapture,
const SDL_AudioSpec *_desired, SDL_AudioSpec *obtained,
int min_id)
{
SDL_AudioDeviceID id = 0;
SDL_AudioSpec desired;
SDL_AudioDevice *device;
int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_SetError("Audio subsystem is not initialized");
return 0;
}
#if defined(__MINT__) && SDL_THREADS_DISABLED
/* Uses interrupt driven audio, without thread */
#else
/* Create a semaphore for locking the sound buffers */
audio->mixer_lock = SDL_CreateMutex();
if (audio->mixer_lock == NULL) {
SDL_SetError("Couldn't create mixer lock");
SDL_CloseAudio();
return (-1);
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
SDL_SetError("No capture support");
return 0;
}
#endif /* __MINT__ */
/* Calculate the silence and size of the audio specification */
SDL_CalculateAudioSpec(desired);
if (!prepare_audiospec(_desired, &desired)) {
return 0;
}
/* Open the audio subsystem */
SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
audio->convert.needed = 0;
audio->enabled = 1;
audio->paused = 1;
/* If app doesn't care about a specific device, let the user override. */
if (devname == NULL) {
devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
}
#if !SDL_AUDIO_DRIVER_AHI
/*
* Catch device names at the high level for the simple case...
* This lets us have a basic "device enumeration" for systems that
* don't have multiple devices, but makes sure the device name is
* always NULL when it hits the low level.
*
* Also make sure that the simple case prevents multiple simultaneous
* opens of the default system device.
*/
/* AmigaOS opens audio inside the main loop */
audio->opened = audio->OpenAudio(audio, &audio->spec) + 1;
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
SDL_SetError("No such device");
return 0;
}
devname = NULL;
if (!audio->opened) {
SDL_CloseAudio();
return (-1);
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if ((open_devices[i]) && (open_devices[i]->iscapture)) {
SDL_SetError("Audio device already open");
return 0;
}
}
}
#else
D(bug("Locking semaphore..."));
SDL_mutexP(audio->mixer_lock);
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
SDL_SetError("No such device");
return 0;
}
devname = NULL;
audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
D(bug("Created thread...\n"));
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
SDL_SetError("Audio device already open");
return 0;
}
}
}
if (audio->thread == NULL) {
SDL_mutexV(audio->mixer_lock);
SDL_CloseAudio();
SDL_SetError("Couldn't create audio thread");
return (-1);
device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof (SDL_AudioDevice));
if (device == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(device, '\0', sizeof (SDL_AudioDevice));
SDL_memcpy(&device->spec, &desired, sizeof (SDL_AudioSpec));
device->enabled = 1;
device->paused = 1;
device->iscapture = iscapture;
while (!audio_configured)
SDL_Delay(100);
#endif
/* Create a semaphore for locking the sound buffers */
if (!current_audio.impl.SkipMixerLock) {
device->mixer_lock = SDL_CreateMutex();
if (device->mixer_lock == NULL) {
close_audio_device(device);
SDL_SetError("Couldn't create mixer lock");
return 0;
}
}
if (!current_audio.impl.OpenDevice(device, devname, iscapture)) {
close_audio_device(device);
return 0;
}
device->opened = 1;
/* If the audio driver changes the buffer size, accept it */
if (audio->spec.samples != desired->samples) {
desired->samples = audio->spec.samples;
SDL_CalculateAudioSpec(desired);
if (device->spec.samples != desired.samples) {
desired.samples = device->spec.samples;
SDL_CalculateAudioSpec(&device->spec);
}
/* Allocate a fake audio memory buffer */
audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
if (audio->fake_stream == NULL) {
SDL_CloseAudio();
device->fake_stream = SDL_AllocAudioMem(device->spec.size);
if (device->fake_stream == NULL) {
close_audio_device(device);
SDL_OutOfMemory();
return (-1);
return 0;
}
/* See if we need to do any conversion */
if (obtained != NULL) {
SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
} else if (desired->freq != audio->spec.freq ||
desired->format != audio->spec.format ||
desired->channels != audio->spec.channels) {
SDL_memcpy(obtained, &device->spec, sizeof(SDL_AudioSpec));
} else if (desired.freq != device->spec.freq ||
desired.format != device->spec.format ||
desired.channels != device->spec.channels) {
/* Build an audio conversion block */
if (SDL_BuildAudioCVT(&audio->convert,
desired->format, desired->channels,
desired->freq,
audio->spec.format, audio->spec.channels,
audio->spec.freq) < 0) {
SDL_CloseAudio();
return (-1);
if (SDL_BuildAudioCVT(&device->convert,
desired.format, desired.channels,
desired.freq,
device->spec.format, device->spec.channels,
device->spec.freq) < 0) {
close_audio_device(device);
return 0;
}
if (audio->convert.needed) {
audio->convert.len = desired->size;
audio->convert.buf =
(Uint8 *) SDL_AllocAudioMem(audio->convert.len *
audio->convert.len_mult);
if (audio->convert.buf == NULL) {
SDL_CloseAudio();
if (device->convert.needed) {
device->convert.len = desired.size;
device->convert.buf =
(Uint8 *) SDL_AllocAudioMem(device->convert.len *
device->convert.len_mult);
if (device->convert.buf == NULL) {
close_audio_device(device);
SDL_OutOfMemory();
return (-1);
return 0;
}
}
}
#if !SDL_AUDIO_DRIVER_AHI
/* Find an available device ID and store the structure... */
for (id = min_id-1; id < SDL_arraysize(open_devices); id++) {
if (open_devices[id] == NULL) {
open_devices[id] = device;
break;
}
}
if (id == SDL_arraysize(open_devices)) {
SDL_SetError("Too many open audio devices");
close_audio_device(device);
return 0;
}
/* Start the audio thread if necessary */
switch (audio->opened) {
case 1:
if (!current_audio.impl.ProvidesOwnCallbackThread) {
/* Start the audio thread */
/* !!! FIXME: this is nasty. */
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL);
#else
audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
device->thread = SDL_CreateThread(SDL_RunAudio, device);
#endif
if (audio->thread == NULL) {
SDL_CloseAudio();
if (device->thread == NULL) {
SDL_CloseAudioDevice(id+1);
SDL_SetError("Couldn't create audio thread");
return 0;
}
}
return id+1;
}
int
SDL_OpenAudio(const SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
{
SDL_AudioDeviceID id = 0;
/* Start up the audio driver, if necessary. This is legacy behaviour! */
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
return (-1);
}
break;
}
default:
/* The audio is now playing */
break;
/* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
if (open_devices[0] != NULL) {
SDL_SetError("Audio device is already opened");
return (-1);
}
#else
SDL_mutexV(audio->mixer_lock);
D(bug("SDL_OpenAudio USCITA...\n"));
#endif
id = open_audio_device(NULL, 0, desired, obtained, 1);
if (id > 1) { /* this should never happen in theory... */
SDL_CloseAudioDevice(id);
SDL_SetError("Internal error"); /* MUST be Device ID #1! */
return (-1);
}
return (0);
return ((id == 0) ? -1 : 0);
}
SDL_audiostatus
SDL_GetAudioStatus(void)
SDL_AudioDeviceID
SDL_OpenAudioDevice(const char *device, int iscapture,
const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{
SDL_AudioDevice *audio = current_audio;
SDL_audiostatus status;
return open_audio_device(device, iscapture, desired, obtained, 2);
}
status = SDL_AUDIO_STOPPED;
if (audio && audio->enabled) {
if (audio->paused) {
SDL_audiostatus
SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
{
SDL_AudioDevice *device = get_audio_device(devid);
SDL_audiostatus status = SDL_AUDIO_STOPPED;
if (device && device->enabled) {
if (device->paused) {
status = SDL_AUDIO_PAUSED;
} else {
status = SDL_AUDIO_PLAYING;
......@@ -669,74 +785,89 @@ SDL_GetAudioStatus(void)
return (status);
}
SDL_audiostatus
SDL_GetAudioStatus(void)
{
return SDL_GetAudioDeviceStatus(1);
}
void
SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
{
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
device->paused = pause_on;
}
}
void
SDL_PauseAudio(int pause_on)
{
SDL_AudioDevice *audio = current_audio;
SDL_PauseAudioDevice(1, pause_on);
}
if (audio) {
audio->paused = pause_on;
void
SDL_LockAudioDevice(SDL_AudioDeviceID devid)
{
/* Obtain a lock on the mixing buffers */
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
current_audio.impl.LockDevice(device);
}
}
void
SDL_LockAudio(void)
{
SDL_AudioDevice *audio = current_audio;
SDL_LockAudioDevice(1);
}
void
SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
{
/* Obtain a lock on the mixing buffers */
if (audio && audio->LockAudio) {
audio->LockAudio(audio);
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
current_audio.impl.UnlockDevice(device);
}
}
void
SDL_UnlockAudio(void)
{
SDL_AudioDevice *audio = current_audio;
SDL_UnlockAudioDevice(1);
}
/* Release lock on the mixing buffers */
if (audio && audio->UnlockAudio) {
audio->UnlockAudio(audio);
void
SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
{
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
close_audio_device(device);
open_devices[devid-1] = NULL;
}
}
void
SDL_CloseAudio(void)
{
SDL_QuitSubSystem(SDL_INIT_AUDIO);
SDL_CloseAudioDevice(1);
}
void
SDL_AudioQuit(void)
{
SDL_AudioDevice *audio = current_audio;
if (audio) {
audio->enabled = 0;
if (audio->thread != NULL) {
SDL_WaitThread(audio->thread, NULL);
}
if (audio->mixer_lock != NULL) {
SDL_DestroyMutex(audio->mixer_lock);
}
if (audio->fake_stream != NULL) {
SDL_FreeAudioMem(audio->fake_stream);
}
if (audio->convert.needed) {
SDL_FreeAudioMem(audio->convert.buf);
}
#if !SDL_AUDIO_DRIVER_AHI
if (audio->opened) {
audio->CloseAudio(audio);
audio->opened = 0;
}
#endif
/* Free the driver data */
audio->free(audio);
current_audio = NULL;
SDL_AudioDeviceID i;
for (i = 0; i < SDL_arraysize(open_devices); i++) {
SDL_CloseAudioDevice(i);
}
/* Free the driver data */
current_audio.impl.Deinitialize();
SDL_memset(&current_audio, '\0', sizeof (current_audio));
SDL_memset(open_devices, '\0', sizeof (open_devices));
}
#define NUM_FORMATS 10
......@@ -797,9 +928,30 @@ SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
spec->silence = 0x00;
break;
}
spec->size = (spec->format & 0xFF) / 8;
spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
spec->size *= spec->channels;
spec->size *= spec->samples;
}
/*
* Moved here from SDL_mixer.c, since it relies on internals of an opened
* audio device (and is deprecated, by the way!).
*/
void
SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
{
/* Mix the user-level audio format */
SDL_AudioDevice *device = get_audio_device(1);
if (device != NULL) {
SDL_AudioFormat format;
if (device->convert.needed) {
format = device->convert.src_format;
} else {
format = device->spec.format;
}
SDL_MixAudioFormat(dst, src, format, len, volume);
}
}
/* vi: set ts=4 sw=4 expandtab: */
......@@ -159,21 +159,19 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
float *dst = (float *) cvt->buf;
if (SDL_AUDIO_ISBIGENDIAN(format)) {
for (i = cvt->len_cvt / 8; i; --i, src += 2) {
float src1, src2;
src1 = SDL_SwapFloatBE(src[0]);
src2 = SDL_SwapFloatBE(src[1]);
const float src1 = SDL_SwapFloatBE(src[0]);
const float src2 = SDL_SwapFloatBE(src[1]);
const double added = ((double) src1) + ((double) src2);
src1 = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatBE(src1);
const float halved = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatBE(halved);
}
} else {
for (i = cvt->len_cvt / 8; i; --i, src += 2) {
float src1, src2;
src1 = SDL_SwapFloatLE(src[0]);
src2 = SDL_SwapFloatLE(src[1]);
const float src1 = SDL_SwapFloatLE(src[0]);
const float src2 = SDL_SwapFloatLE(src[1]);
const double added = ((double) src1) + ((double) src2);
src1 = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatLE(src1);
const float halved = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatLE(halved);
}
}
}
......
......@@ -46,14 +46,63 @@
#define _PATH_DEV_AUDIO "/dev/audio"
#endif
static inline void
test_device(const char *fname, int flags, int (*test)(int fd),
char ***devices, int *devCount)
{
struct stat sb;
if ( (stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode)) ) {
int audio_fd = open(fname, flags, 0);
if ( (audio_fd >= 0) && (test(audio_fd)) ) {
void *p = SDL_realloc(*devices, ((*devCount)+1) * sizeof (char *));
if (p != NULL) {
size_t len = strlen(fname) + 1;
char *str = (char *) SDL_malloc(len);
*devices = (char **) p;
if (str != NULL) {
SDL_strlcpy(str, fname, len);
(*devices)[(*devCount)++] = str;
}
}
close(audio_fd);
}
}
}
int
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
void
SDL_FreeUnixAudioDevices(char ***devices, int *devCount)
{
int i = *devCount;
if ((i > 0) && (*devices != NULL)) {
while (i--) {
SDL_free( (*devices)[*devCount] );
}
}
if (*devices != NULL) {
SDL_free(*devices);
}
*devices = NULL;
*devCount = 0;
}
static int
test_stub(int fd)
{
return 1;
}
void
SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
char ***devices, int *devCount)
{
const char *audiodev;
int audio_fd;
char audiopath[1024];
if (test == NULL)
test = test_stub;
/* Figure out what our audio device is */
if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
......@@ -72,111 +121,16 @@ SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
}
}
}
audio_fd = open(audiodev, flags, 0);
/* If the first open fails, look for other devices */
if ((audio_fd < 0) && (SDL_strlen(audiodev) < (sizeof(audiopath) - 3))) {
int exists, instance;
struct stat sb;
test_device(audiodev, flags, test, devices, devCount);
instance = 1;
do { /* Don't use errno ENOENT - it may not be thread-safe */
if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
int instance = 0;
while (instance++ <= 64) {
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
"%s%d", audiodev, instance++);
exists = 0;
if (stat(audiopath, &sb) == 0) {
exists = 1;
audio_fd = open(audiopath, flags, 0);
}
}
while (exists && (audio_fd < 0));
audiodev = audiopath;
}
if (path != NULL) {
SDL_strlcpy(path, audiodev, maxlen);
path[maxlen - 1] = '\0';
}
return (audio_fd);
}
#elif SDL_AUDIO_DRIVER_PAUD
/* Get the name of the audio device we use for output */
#include <sys/types.h>
#include <sys/stat.h>
#include "SDL_stdinc.h"
#include "SDL_audiodev_c.h"
#ifndef _PATH_DEV_DSP
#define _PATH_DEV_DSP "/dev/%caud%c/%c"
#endif
char devsettings[][3] = {
{'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
{'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
{'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
{'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
{'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
{'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
{'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
{'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
{'\0', '\0', '\0'}
};
static int
OpenUserDefinedDevice(char *path, int maxlen, int flags)
{
const char *audiodev;
int audio_fd;
/* Figure out what our audio device is */
if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
audiodev = SDL_getenv("AUDIODEV");
}
if (audiodev == NULL) {
return -1;
}
audio_fd = open(audiodev, flags, 0);
if (path != NULL) {
SDL_strlcpy(path, audiodev, maxlen);
path[maxlen - 1] = '\0';
}
return audio_fd;
}
int
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
{
struct stat sb;
int audio_fd;
char audiopath[1024];
int cycle;
audio_fd = OpenUserDefinedDevice(path, maxlen, flags);
if (audio_fd != -1) {
return audio_fd;
}
cycle = 0;
while (devsettings[cycle][0] != '\0') {
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
_PATH_DEV_DSP,
devsettings[cycle][0],
devsettings[cycle][1], devsettings[cycle][2]);
if (stat(audiopath, &sb) == 0) {
audio_fd = open(audiopath, flags, 0);
if (audio_fd > 0) {
if (path != NULL) {
SDL_strlcpy(path, audiopath, maxlen);
}
return audio_fd;
}
"%s%d", audiodev, instance);
test_device(audiopath, flags, test, devices, devCount);
}
}
return -1;
}
#endif /* Audio driver selection */
......
......@@ -21,6 +21,8 @@
*/
#include "SDL_config.h"
/* Open the audio device, storing the pathname in 'path' */
extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic);
void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
char ***devs, int *count);
void SDL_FreeUnixAudioDevices(char ***devices, int *devCount);
/* vi: set ts=4 sw=4 expandtab: */
......@@ -89,21 +89,6 @@ static const Uint8 mix8[] = {
#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
void
SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
{
/* Mix the user-level audio format */
if (current_audio) {
SDL_AudioFormat format;
if (current_audio->convert.needed) {
format = current_audio->convert.src_format;
} else {
format = current_audio->spec.format;
}
SDL_MixAudioFormat(dst, src, format, len, volume);
}
}
void
SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
......
......@@ -29,13 +29,33 @@
/* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice;
/* Define the SDL audio driver structure */
#define _THIS SDL_AudioDevice *_this
#ifndef _STATUS
#define _STATUS SDL_status *status
#endif
struct SDL_AudioDevice
typedef struct SDL_AudioDriverImpl
{
int (*DetectDevices)(int iscapture);
const char *(*GetDeviceName)(int index, int iscapture);
int (*OpenDevice) (_THIS, const char *devname, int iscapture);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS);
Uint8 *(*GetDeviceBuf) (_THIS);
void (*WaitDone) (_THIS);
void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS);
void (*Deinitialize) (void);
/* Some flags to push duplicate code into the core and reduce #ifdefs. */
int ProvidesOwnCallbackThread:1;
int SkipMixerLock:1;
int HasCaptureSupport:1;
int OnlyHasDefaultOutputDevice:1;
int OnlyHasDefaultInputDevice:1;
} SDL_AudioDriverImpl;
typedef struct SDL_AudioDriver
{
/* * * */
/* The name of this audio driver */
......@@ -45,21 +65,13 @@ struct SDL_AudioDevice
/* The description of this audio driver */
const char *desc;
/* * * */
/* Public driver functions */
int (*OpenAudio) (_THIS, SDL_AudioSpec * spec);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*WaitAudio) (_THIS);
void (*PlayAudio) (_THIS);
Uint8 *(*GetAudioBuf) (_THIS);
void (*WaitDone) (_THIS);
void (*CloseAudio) (_THIS);
SDL_AudioDriverImpl impl;
} SDL_AudioDriver;
/* * * */
/* Lock / Unlock functions added for the Mac port */
void (*LockAudio) (_THIS);
void (*UnlockAudio) (_THIS);
/* Define the SDL audio driver structure */
struct SDL_AudioDevice
{
/* * * */
/* Data common to all devices */
......@@ -70,6 +82,7 @@ struct SDL_AudioDevice
SDL_AudioCVT convert;
/* Current state flags */
int iscapture;
int enabled;
int paused;
int opened;
......@@ -87,10 +100,6 @@ struct SDL_AudioDevice
/* * * */
/* Data private to this driver */
struct SDL_PrivateAudioData *hidden;
/* * * */
/* The function used to dispose of this structure */
void (*free) (_THIS);
};
#undef _THIS
......@@ -98,84 +107,10 @@ typedef struct AudioBootStrap
{
const char *name;
const char *desc;
int (*available) (void);
SDL_AudioDevice *(*create) (int devindex);
int (*init) (SDL_AudioDriverImpl *impl);
int demand_only:1; /* 1==request explicitly, or it won't be available. */
} AudioBootStrap;
#if SDL_AUDIO_DRIVER_BSD
extern AudioBootStrap BSD_AUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_OSS
extern AudioBootStrap DSP_bootstrap;
extern AudioBootStrap DMA_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_ALSA
extern AudioBootStrap ALSA_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_QNXNTO
extern AudioBootStrap QNXNTOAUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_SUNAUDIO
extern AudioBootStrap SUNAUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DMEDIA
extern AudioBootStrap DMEDIA_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_ARTS
extern AudioBootStrap ARTS_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_ESD
extern AudioBootStrap ESD_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_NAS
extern AudioBootStrap NAS_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DSOUND
extern AudioBootStrap DSOUND_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_WAVEOUT
extern AudioBootStrap WAVEOUT_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_PAUD
extern AudioBootStrap Paud_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_BAUDIO
extern AudioBootStrap BAUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_COREAUDIO
extern AudioBootStrap COREAUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_SNDMGR
extern AudioBootStrap SNDMGR_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_AHI
extern AudioBootStrap AHI_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_MINT
extern AudioBootStrap MINTAUDIO_GSXB_bootstrap;
extern AudioBootStrap MINTAUDIO_MCSN_bootstrap;
extern AudioBootStrap MINTAUDIO_STFA_bootstrap;
extern AudioBootStrap MINTAUDIO_XBIOS_bootstrap;
extern AudioBootStrap MINTAUDIO_DMA8_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DISK
extern AudioBootStrap DISKAUD_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DUMMY
extern AudioBootStrap DUMMYAUD_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DC
extern AudioBootStrap DCAUD_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_MMEAUDIO
extern AudioBootStrap MMEAUDIO_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_DART
extern AudioBootStrap DART_bootstrap;
#endif
/* This is the current audio device */
extern SDL_AudioDevice *current_audio;
#endif /* _SDL_sysaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -25,6 +25,9 @@
#include <sys/types.h>
#include <signal.h> /* For kill() */
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
......@@ -32,14 +35,6 @@
#include "../SDL_audio_c.h"
#include "SDL_alsa_audio.h"
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#include <dlfcn.h>
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
/* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa"
......@@ -47,182 +42,138 @@
/* The default ALSA audio driver */
#define DEFAULT_DEVICE "default"
/* Audio driver functions */
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void ALSA_WaitAudio(_THIS);
static void ALSA_PlayAudio(_THIS);
static Uint8 *ALSA_GetAudioBuf(_THIS);
static void ALSA_CloseAudio(_THIS);
static int (*ALSA_snd_pcm_open)
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm);
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
(snd_pcm_t *,const void *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_resume)(snd_pcm_t *);
static int (*ALSA_snd_pcm_prepare)(snd_pcm_t *);
static int (*ALSA_snd_pcm_drain)(snd_pcm_t *);
static const char *(*ALSA_snd_strerror)(int);
static size_t(*ALSA_snd_pcm_hw_params_sizeof)(void);
static size_t(*ALSA_snd_pcm_sw_params_sizeof)(void);
static int (*ALSA_snd_pcm_hw_params_any)(snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params_set_access)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
static int (*ALSA_snd_pcm_hw_params_set_format)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
static int (*ALSA_snd_pcm_hw_params_set_channels)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
static int (*ALSA_snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *);
static unsigned int (*ALSA_snd_pcm_hw_params_set_rate_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *);
static snd_pcm_uframes_t (*ALSA_snd_pcm_hw_params_set_period_size_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t, int *);
static snd_pcm_sframes_t (*ALSA_snd_pcm_hw_params_get_period_size)
(const snd_pcm_hw_params_t *);
static unsigned int (*ALSA_snd_pcm_hw_params_set_periods_near)
(snd_pcm_t *,snd_pcm_hw_params_t *, unsigned int, int *);
static int (*ALSA_snd_pcm_hw_params_get_periods)(snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_sw_params_current)(snd_pcm_t*, snd_pcm_sw_params_t*);
static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_sw_params)(snd_pcm_t *, snd_pcm_sw_params_t *);
static int (*ALSA_snd_pcm_nonblock)(snd_pcm_t *, int);
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
#define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
static void *alsa_handle = NULL;
static int alsa_loaded = 0;
static int (*SDL_snd_pcm_open) (snd_pcm_t ** pcm, const char *name,
snd_pcm_stream_t stream, int mode);
static int (*SDL_NAME(snd_pcm_open)) (snd_pcm_t ** pcm, const char *name,
snd_pcm_stream_t stream, int mode);
static int (*SDL_NAME(snd_pcm_close)) (snd_pcm_t * pcm);
static snd_pcm_sframes_t(*SDL_NAME(snd_pcm_writei)) (snd_pcm_t * pcm,
const void *buffer,
snd_pcm_uframes_t size);
static int (*SDL_NAME(snd_pcm_resume)) (snd_pcm_t * pcm);
static int (*SDL_NAME(snd_pcm_prepare)) (snd_pcm_t * pcm);
static int (*SDL_NAME(snd_pcm_drain)) (snd_pcm_t * pcm);
static const char *(*SDL_NAME(snd_strerror)) (int errnum);
static size_t(*SDL_NAME(snd_pcm_hw_params_sizeof)) (void);
static size_t(*SDL_NAME(snd_pcm_sw_params_sizeof)) (void);
static int (*SDL_NAME(snd_pcm_hw_params_any)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t * params);
static int (*SDL_NAME(snd_pcm_hw_params_set_access)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t *
params,
snd_pcm_access_t
access);
static int (*SDL_NAME(snd_pcm_hw_params_set_format)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t *
params,
snd_pcm_format_t val);
static int (*SDL_NAME(snd_pcm_hw_params_set_channels)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t *
params,
unsigned int val);
static int (*SDL_NAME(snd_pcm_hw_params_get_channels)) (const
snd_pcm_hw_params_t *
params);
static unsigned int
(*SDL_NAME(snd_pcm_hw_params_set_rate_near)) (snd_pcm_t *
pcm,
snd_pcm_hw_params_t
* params,
unsigned int val, int *dir);
static snd_pcm_uframes_t
(*SDL_NAME(snd_pcm_hw_params_set_period_size_near)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t
* params,
snd_pcm_uframes_t
val, int *dir);
static snd_pcm_sframes_t
(*SDL_NAME(snd_pcm_hw_params_get_period_size)) (const
snd_pcm_hw_params_t
* params);
static unsigned int
(*SDL_NAME(snd_pcm_hw_params_set_periods_near)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t
* params,
unsigned int val,
int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_get_periods)) (snd_pcm_hw_params_t *
params);
static int (*SDL_NAME(snd_pcm_hw_params)) (snd_pcm_t * pcm,
snd_pcm_hw_params_t * params);
/*
*/
static int (*SDL_NAME(snd_pcm_sw_params_current)) (snd_pcm_t * pcm,
snd_pcm_sw_params_t *
swparams);
static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold)) (snd_pcm_t *
pcm,
snd_pcm_sw_params_t
* params,
snd_pcm_uframes_t
val);
static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min)) (snd_pcm_t * pcm,
snd_pcm_sw_params_t
* params,
snd_pcm_uframes_t
val);
static int (*SDL_NAME(snd_pcm_sw_params)) (snd_pcm_t * pcm,
snd_pcm_sw_params_t * params);
static int (*SDL_NAME(snd_pcm_nonblock)) (snd_pcm_t * pcm, int nonblock);
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
static struct
static int
load_alsa_sym(const char *fn, void **addr)
{
const char *name;
void **func;
} alsa_functions[] = {
{
"snd_pcm_open", (void **) (char *) &SDL_NAME(snd_pcm_open)}, {
"snd_pcm_close", (void **) (char *) &SDL_NAME(snd_pcm_close)}, {
"snd_pcm_writei", (void **) (char *) &SDL_NAME(snd_pcm_writei)}, {
"snd_pcm_resume", (void **) (char *) &SDL_NAME(snd_pcm_resume)}, {
"snd_pcm_prepare", (void **) (char *) &SDL_NAME(snd_pcm_prepare)}, {
"snd_pcm_drain", (void **) (char *) &SDL_NAME(snd_pcm_drain)}, {
"snd_strerror", (void **) (char *) &SDL_NAME(snd_strerror)}, {
"snd_pcm_hw_params_sizeof",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_sizeof)}, {
"snd_pcm_sw_params_sizeof",
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_sizeof)}, {
"snd_pcm_hw_params_any",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_any)}, {
"snd_pcm_hw_params_set_access",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_access)}, {
"snd_pcm_hw_params_set_format",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_format)}, {
"snd_pcm_hw_params_set_channels",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_channels)}, {
"snd_pcm_hw_params_get_channels",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_channels)}, {
"snd_pcm_hw_params_set_rate_near",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_rate_near)}, {
"snd_pcm_hw_params_set_period_size_near", (void **) (char *)
&SDL_NAME(snd_pcm_hw_params_set_period_size_near)}, {
"snd_pcm_hw_params_get_period_size",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_period_size)},
/*
* !!! FIXME:
* Eventually, this will deal with fallbacks, version changes, and
* missing symbols we can workaround. But for now, it doesn't.
*/
#if HAVE_DLVSYM
*addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
if (*addr == NULL)
#endif
{
"snd_pcm_hw_params_set_periods_near", (void **) (char *)
&SDL_NAME(snd_pcm_hw_params_set_periods_near)}, {
"snd_pcm_hw_params_get_periods",
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_periods)}, {
"snd_pcm_hw_params", (void **) (char *) &SDL_NAME(snd_pcm_hw_params)}, {
"snd_pcm_sw_params_current",
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_current)}, {
"snd_pcm_sw_params_set_start_threshold", (void **) (char *)
&SDL_NAME(snd_pcm_sw_params_set_start_threshold)}, {
"snd_pcm_sw_params_set_avail_min",
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_set_avail_min)}, {
"snd_pcm_sw_params", (void **) (char *) &SDL_NAME(snd_pcm_sw_params)}, {
"snd_pcm_nonblock", (void **) (char *) &SDL_NAME(snd_pcm_nonblock)},};
*addr = dlsym(alsa_handle, fn);
if (*addr == NULL) {
SDL_SetError("dlsym('%s') failed: %s", fn, strerror(errno));
return 0;
}
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_ALSA_SYM(x) \
if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
#else
#define SDL_ALSA_SYM(x) ALSA_##x = x
#endif
static int load_alsa_syms(void)
{
SDL_ALSA_SYM(snd_pcm_open);
SDL_ALSA_SYM(snd_pcm_close);
SDL_ALSA_SYM(snd_pcm_writei);
SDL_ALSA_SYM(snd_pcm_resume);
SDL_ALSA_SYM(snd_pcm_prepare);
SDL_ALSA_SYM(snd_pcm_drain);
SDL_ALSA_SYM(snd_strerror);
SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_hw_params_any);
SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
SDL_ALSA_SYM(snd_pcm_hw_params);
SDL_ALSA_SYM(snd_pcm_sw_params_current);
SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
SDL_ALSA_SYM(snd_pcm_sw_params);
SDL_ALSA_SYM(snd_pcm_nonblock);
return 0;
}
#undef SDL_ALSA_SYM
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static void
UnloadALSALibrary(void)
{
if (alsa_loaded) {
/* SDL_UnloadObject(alsa_handle);*/
if (alsa_handle != NULL) {
dlclose(alsa_handle);
alsa_handle = NULL;
alsa_loaded = 0;
}
}
static int
LoadALSALibrary(void)
{
int i, retval = -1;
/* alsa_handle = SDL_LoadObject(alsa_library);*/
alsa_handle = dlopen(alsa_library, RTLD_NOW);
if (alsa_handle) {
alsa_loaded = 1;
retval = 0;
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
/* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/
#if HAVE_DLVSYM
*alsa_functions[i].func =
dlvsym(alsa_handle, alsa_functions[i].name, "ALSA_0.9");
if (!*alsa_functions[i].func)
#endif
*alsa_functions[i].func =
dlsym(alsa_handle, alsa_functions[i].name);
if (!*alsa_functions[i].func) {
retval = -1;
int retval = 0;
if (alsa_handle == NULL) {
alsa_handle = dlopen(alsa_library, RTLD_NOW);
if (alsa_handle == NULL) {
retval = -1;
SDL_SetError("ALSA: dlopen('%s') failed: %s\n",
alsa_library, strerror(errno));
} else {
retval = load_alsa_syms();
if (retval < 0) {
UnloadALSALibrary();
break;
}
}
}
......@@ -234,12 +185,12 @@ LoadALSALibrary(void)
static void
UnloadALSALibrary(void)
{
return;
}
static int
LoadALSALibrary(void)
{
load_alsa_syms();
return 0;
}
......@@ -262,80 +213,10 @@ get_audio_device(int channels)
return device;
}
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int available;
int status;
snd_pcm_t *handle;
available = 0;
if (LoadALSALibrary() < 0) {
return available;
}
status =
SDL_NAME(snd_pcm_open) (&handle, get_audio_device(2),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (status >= 0) {
available = 1;
SDL_NAME(snd_pcm_close) (handle);
}
UnloadALSALibrary();
return (available);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadALSALibrary();
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadALSALibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ALSA_bootstrap = {
DRIVER_NAME, "ALSA 0.9 PCM audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
ALSA_WaitAudio(_THIS)
ALSA_WaitDevice(_THIS)
{
/* Check to see if the thread-parent process is still alive */
{
......@@ -343,8 +224,9 @@ ALSA_WaitAudio(_THIS)
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0;
}
}
......@@ -352,13 +234,14 @@ ALSA_WaitAudio(_THIS)
}
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T) \
T *ptr = (T *) mixbuf; \
T *ptr = (T *) this->hidden->mixbuf; \
const Uint32 count = (this->spec.samples / 6); \
Uint32 i; \
for (i = 0; i < count; i++, ptr += 6) { \
......@@ -392,8 +275,8 @@ swizzle_alsa_channels_6_8bit(_THIS)
/*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
* from Windows/Mac order to the format alsalib will want.
* Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
* channels from Windows/Mac order to the format alsalib will want.
*/
static __inline__ void
swizzle_alsa_channels(_THIS)
......@@ -415,7 +298,7 @@ swizzle_alsa_channels(_THIS)
static void
ALSA_PlayAudio(_THIS)
ALSA_PlayDevice(_THIS)
{
int status;
int sample_len;
......@@ -424,11 +307,12 @@ ALSA_PlayAudio(_THIS)
swizzle_alsa_channels(this);
sample_len = this->spec.samples;
sample_buf = (signed short *) mixbuf;
sample_buf = (signed short *) this->hidden->mixbuf;
while (sample_len > 0) {
status =
SDL_NAME(snd_pcm_writei) (pcm_handle, sample_buf, sample_len);
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
sample_buf, sample_len);
if (status < 0) {
if (status == -EAGAIN) {
SDL_Delay(1);
......@@ -437,11 +321,11 @@ ALSA_PlayAudio(_THIS)
if (status == -ESTRPIPE) {
do {
SDL_Delay(1);
status = SDL_NAME(snd_pcm_resume) (pcm_handle);
status = ALSA_snd_pcm_resume(this->hidden->pcm_handle);
} while (status == -EAGAIN);
}
if (status < 0) {
status = SDL_NAME(snd_pcm_prepare) (pcm_handle);
status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle);
}
if (status < 0) {
/* Hmm, not much we can do - abort */
......@@ -456,74 +340,89 @@ ALSA_PlayAudio(_THIS)
}
static Uint8 *
ALSA_GetAudioBuf(_THIS)
ALSA_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}
static void
ALSA_CloseAudio(_THIS)
ALSA_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (pcm_handle) {
SDL_NAME(snd_pcm_drain) (pcm_handle);
SDL_NAME(snd_pcm_close) (pcm_handle);
pcm_handle = NULL;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->pcm_handle) {
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
ALSA_snd_pcm_close(this->hidden->pcm_handle);
this->hidden->pcm_handle = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
{
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_format_t format;
snd_pcm_uframes_t frames;
SDL_AudioFormat test_format;
int status = 0;
snd_pcm_t *pcm_handle = NULL;
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_format_t format = 0;
snd_pcm_uframes_t frames = 0;
SDL_AudioFormat test_format = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Open the audio device */
/* Name of device should depend on # channels in spec */
status =
SDL_NAME(snd_pcm_open) (&pcm_handle,
get_audio_device(spec->channels),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(this->spec.channels),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (status < 0) {
SDL_SetError("Couldn't open audio device: %s",
SDL_NAME(snd_strerror) (status));
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't open audio device: %s",
ALSA_snd_strerror(status));
return 0;
}
this->hidden->pcm_handle = pcm_handle;
/* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams);
status = SDL_NAME(snd_pcm_hw_params_any) (pcm_handle, hwparams);
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
if (status < 0) {
SDL_SetError("Couldn't get hardware config: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't get hardware config: %s",
ALSA_snd_strerror(status));
return 0;
}
/* SDL only uses interleaved sample output */
status =
SDL_NAME(snd_pcm_hw_params_set_access) (pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (status < 0) {
SDL_SetError("Couldn't set interleaved access: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set interleaved access: %s",
ALSA_snd_strerror(status));
return 0;
}
/* Try for a closest match on audio format */
status = -1;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
test_format && (status < 0);) {
status = 0; /* if we can't support a format, it'll become -1. */
status = 0; /* if we can't support a format, it'll become -1. */
switch (test_format) {
case AUDIO_U8:
format = SND_PCM_FORMAT_U8;
......@@ -560,131 +459,151 @@ ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
break;
}
if (status >= 0) {
status =
SDL_NAME(snd_pcm_hw_params_set_format) (pcm_handle,
hwparams, format);
status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
hwparams, format);
}
if (status < 0) {
test_format = SDL_NextAudioFormat();
}
}
if (status < 0) {
SDL_SetError("Couldn't find any hardware audio formats");
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't find any hardware audio formats");
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
/* Set the number of channels */
status =
SDL_NAME(snd_pcm_hw_params_set_channels) (pcm_handle, hwparams,
spec->channels);
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
this->spec.channels);
if (status < 0) {
status = SDL_NAME(snd_pcm_hw_params_get_channels) (hwparams);
status = ALSA_snd_pcm_hw_params_get_channels(hwparams);
if ((status <= 0) || (status > 2)) {
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set audio channels");
return 0;
}
spec->channels = status;
this->spec.channels = status;
}
/* Set the audio rate */
status =
SDL_NAME(snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams,
spec->freq, NULL);
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
this->spec.freq, NULL);
if (status < 0) {
SDL_SetError("Couldn't set audio frequency: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set audio frequency: %s",
ALSA_snd_strerror(status));
return 0;
}
spec->freq = status;
this->spec.freq = status;
/* Set the buffer size, in samples */
frames = spec->samples;
frames =
SDL_NAME(snd_pcm_hw_params_set_period_size_near) (pcm_handle,
hwparams, frames,
NULL);
spec->samples = frames;
SDL_NAME(snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2,
NULL);
frames = this->spec.samples;
frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
frames, NULL);
this->spec.samples = frames;
ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);
/* "set" the hardware with the desired parameters */
status = SDL_NAME(snd_pcm_hw_params) (pcm_handle, hwparams);
status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
if (status < 0) {
SDL_SetError("Couldn't set hardware audio parameters: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s",
ALSA_snd_strerror(status));
return 0;
}
/* This is useful for debugging... */
/*
{ snd_pcm_sframes_t bufsize; int fragments;
bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams);
fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams);
fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
#if AUDIO_DEBUG
{
snd_pcm_sframes_t bufsize;
int fragments;
bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams);
fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams);
fprintf(stderr,"ALSA: bufsize = %ld, fragments = %d\n",bufsize,fragments);
}
*/
#endif
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = SDL_NAME(snd_pcm_sw_params_current) (pcm_handle, swparams);
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
if (status < 0) {
SDL_SetError("Couldn't get software config: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't get software config: %s",
ALSA_snd_strerror(status));
return 0;
}
status =
SDL_NAME(snd_pcm_sw_params_set_start_threshold) (pcm_handle,
swparams, 0);
status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0);
if (status < 0) {
SDL_SetError("Couldn't set start threshold: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("ALSA: Couldn't set start threshold: %s",
ALSA_snd_strerror(status));
return 0;
}
status =
SDL_NAME(snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams,
frames);
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
if (status < 0) {
SDL_SetError("Couldn't set avail min: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_CloseDevice(this);
SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
return 0;
}
status = SDL_NAME(snd_pcm_sw_params) (pcm_handle, swparams);
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
if (status < 0) {
ALSA_CloseDevice(this);
SDL_SetError("Couldn't set software audio parameters: %s",
SDL_NAME(snd_strerror) (status));
ALSA_CloseAudio(this);
return (-1);
ALSA_snd_strerror(status));
return 0;
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
ALSA_CloseAudio(this);
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ALSA_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
this->hidden->parent = getpid();
/* Switch to blocking mode for playback */
SDL_NAME(snd_pcm_nonblock) (pcm_handle, 0);
ALSA_snd_pcm_nonblock(pcm_handle, 0);
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static void
ALSA_Deinitialize(void)
{
UnloadALSALibrary();
}
static int
ALSA_Init(SDL_AudioDriverImpl *impl)
{
if (LoadALSALibrary() < 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->Deinitialize = ALSA_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
return 1;
}
AudioBootStrap ALSA_bootstrap = {
DRIVER_NAME, "ALSA 0.9 PCM audio", ALSA_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -30,7 +30,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -46,11 +46,5 @@ struct SDL_PrivateAudioData
int mixlen;
};
/* Old variable names */
#define pcm_handle (this->hidden->pcm_handle)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#endif /* _ALSA_PCM_audio_h */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer (for AmigaOS) */
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_ahiaudio.h"
/* Audio driver functions */
static int AHI_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void AHI_WaitAudio(_THIS);
static void AHI_PlayAudio(_THIS);
static Uint8 *AHI_GetAudioBuf(_THIS);
static void AHI_CloseAudio(_THIS);
#ifndef __SASC
#define mymalloc(x) AllocVec(x,MEMF_PUBLIC)
#define myfree FreeVec
#else
#define mymalloc malloc
#define myfree free
#endif
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int ok = 0;
struct MsgPort *p;
struct AHIRequest *req;
if (p = CreateMsgPort()) {
if (req =
(struct AHIRequest *) CreateIORequest(p,
sizeof(struct
AHIRequest))) {
req->ahir_Version = 4;
if (!OpenDevice(AHINAME, 0, (struct IORequest *) req, NULL)) {
D(bug("AHI available.\n"));
ok = 1;
CloseDevice((struct IORequest *) req);
}
DeleteIORequest((struct IORequest *) req);
}
DeleteMsgPort(p);
}
D(if (!ok) bug("AHI not available\n"));
return ok;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
#ifndef NO_AMIGADEBUG
D(bug("AHI created...\n"));
#endif
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = AHI_OpenAudio;
this->WaitAudio = AHI_WaitAudio;
this->PlayAudio = AHI_PlayAudio;
this->GetAudioBuf = AHI_GetAudioBuf;
this->CloseAudio = AHI_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap AHI_bootstrap = {
"AHI", Audio_Available, Audio_CreateDevice
};
void static
AHI_WaitAudio(_THIS)
{
if (!CheckIO((struct IORequest *) audio_req[current_buffer])) {
WaitIO((struct IORequest *) audio_req[current_buffer]);
// AbortIO((struct IORequest *)audio_req[current_buffer]);
}
}
static void
AHI_PlayAudio(_THIS)
{
if (playing > 1)
WaitIO((struct IORequest *) audio_req[current_buffer]);
/* Write the audio data out */
audio_req[current_buffer]->ahir_Std.io_Message.mn_Node.ln_Pri = 60;
audio_req[current_buffer]->ahir_Std.io_Data = mixbuf[current_buffer];
audio_req[current_buffer]->ahir_Std.io_Length = this->hidden->size;
audio_req[current_buffer]->ahir_Std.io_Offset = 0;
audio_req[current_buffer]->ahir_Std.io_Command = CMD_WRITE;
audio_req[current_buffer]->ahir_Frequency = this->hidden->freq;
audio_req[current_buffer]->ahir_Volume = 0x10000;
audio_req[current_buffer]->ahir_Type = this->hidden->type;
audio_req[current_buffer]->ahir_Position = 0x8000;
audio_req[current_buffer]->ahir_Link =
(playing > 0 ? audio_req[current_buffer ^ 1] : NULL);
SendIO((struct IORequest *) audio_req[current_buffer]);
current_buffer ^= 1;
playing++;
}
static Uint8 *
AHI_GetAudioBuf(_THIS)
{
return (mixbuf[current_buffer]);
}
static void
AHI_CloseAudio(_THIS)
{
D(bug("Closing audio...\n"));
playing = 0;
if (audio_req[0]) {
if (audio_req[1]) {
D(bug("Break req[1]...\n"));
AbortIO((struct IORequest *) audio_req[1]);
WaitIO((struct IORequest *) audio_req[1]);
}
D(bug("Break req[0]...\n"));
AbortIO((struct IORequest *) audio_req[0]);
WaitIO((struct IORequest *) audio_req[0]);
if (audio_req[1]) {
D(bug("Break AGAIN req[1]...\n"));
AbortIO((struct IORequest *) audio_req[1]);
WaitIO((struct IORequest *) audio_req[1]);
}
// Double abort to be sure to break the dbuffering process.
SDL_Delay(200);
D(bug("Reqs breaked, closing device...\n"));
CloseDevice((struct IORequest *) audio_req[0]);
D(bug("Device closed, freeing memory...\n"));
myfree(audio_req[1]);
D(bug("Memory freed, deleting IOReq...\n"));
DeleteIORequest((struct IORequest *) audio_req[0]);
audio_req[0] = audio_req[1] = NULL;
}
D(bug("Freeing mixbuf[0]...\n"));
if (mixbuf[0] != NULL) {
myfree(mixbuf[0]);
// SDL_FreeAudioMem(mixbuf[0]);
mixbuf[0] = NULL;
}
D(bug("Freeing mixbuf[1]...\n"));
if (mixbuf[1] != NULL) {
myfree(mixbuf[1]);
// SDL_FreeAudioMem(mixbuf[1]);
mixbuf[1] = NULL;
}
D(bug("Freeing audio_port...\n"));
if (audio_port != NULL) {
DeleteMsgPort(audio_port);
audio_port = NULL;
}
D(bug("...done!\n"));
}
static int
AHI_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
// int width;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 1;
D(bug("AHI opening...\n"));
/* Determine the audio parameters from the AudioSpec */
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
switch (test_format) {
case AUDIO_S8:
D(bug("AUDIO_S8...\n"));
spec->format = AUDIO_S8;
this->hidden->bytespersample = 1;
if (spec->channels < 2)
this->hidden->type = AHIST_M8S;
else
this->hidden->type = AHIST_S8S;
break;
case AUDIO_S16MSB:
D(bug("AUDIO_S16MSB...\n"));
spec->format = AUDIO_S16MSB;
this->hidden->bytespersample = 2;
if (spec->channels < 2)
this->hidden->type = AHIST_M16S;
else
this->hidden->type = AHIST_S16S;
break;
case AUDIO_S32MSB:
D(bug("AUDIO_S32MSB...\n"));
spec->format = AUDIO_S32MSB;
this->hidden->bytespersample = 4;
if (spec->channels < 2)
this->hidden->type = AHIST_M32S;
else
this->hidden->type = AHIST_S32S;
break;
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format");
return (-1);
}
if (spec->channels > 2) {
spec->channels = 2; /* will convert at higher level. */
}
D(bug("Before CalculateAudioSpec\n"));
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
D(bug("Before CreateMsgPort\n"));
if (!(audio_port = CreateMsgPort())) {
SDL_SetError("Unable to create a MsgPort");
return -1;
}
D(bug("Before CreateIORequest\n"));
if (!
(audio_req[0] =
(struct AHIRequest *) CreateIORequest(audio_port,
sizeof(struct AHIRequest)))) {
SDL_SetError("Unable to create an AHIRequest");
DeleteMsgPort(audio_port);
return -1;
}
audio_req[0]->ahir_Version = 4;
if (OpenDevice(AHINAME, 0, (struct IORequest *) audio_req[0], NULL)) {
SDL_SetError("Unable to open AHI device!\n");
DeleteIORequest((struct IORequest *) audio_req[0]);
DeleteMsgPort(audio_port);
return -1;
}
D(bug("AFTER opendevice\n"));
/* Set output frequency and size */
this->hidden->freq = spec->freq;
this->hidden->size = spec->size;
D(bug("Before buffer allocation\n"));
/* Allocate mixing buffer */
mixbuf[0] = (Uint8 *) mymalloc(spec->size);
mixbuf[1] = (Uint8 *) mymalloc(spec->size);
D(bug("Before audio_req allocation\n"));
if (!(audio_req[1] = mymalloc(sizeof(struct AHIRequest)))) {
SDL_OutOfMemory();
return (-1);
}
D(bug("Before audio_req memcpy\n"));
SDL_memcpy(audio_req[1], audio_req[0], sizeof(struct AHIRequest));
if (mixbuf[0] == NULL || mixbuf[1] == NULL) {
SDL_OutOfMemory();
return (-1);
}
D(bug("Before mixbuf memset\n"));
SDL_memset(mixbuf[0], spec->silence, spec->size);
SDL_memset(mixbuf[1], spec->silence, spec->size);
current_buffer = 0;
playing = 0;
D(bug
("AHI opened: freq:%ld mixbuf:%lx/%lx buflen:%ld bits:%ld channels:%ld\n",
spec->freq, mixbuf[0], mixbuf[1], spec->size,
this->hidden->bytespersample * 8, spec->channels));
/* We're ready to rock and roll. :-) */
return (0);
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_ahiaudio_h
#define _SDL_ahiaudio_h
#include <exec/exec.h>
#include <dos/dos.h>
#ifdef __SASC
#include <proto/exec.h>
#else
#include <inline/exec.h>
#endif
#include <devices/ahi.h>
#include "mydebug.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The handle for the audio device */
struct AHIRequest *audio_req[2];
struct MsgPort *audio_port;
Sint32 freq, type, bytespersample, size;
Uint8 *mixbuf[2]; /* The app mixing buffer */
int current_buffer;
Uint32 playing;
};
/* Old variable names */
#define audio_port (this->hidden->audio_port)
#define audio_req (this->hidden->audio_req)
#define mixbuf (this->hidden->mixbuf)
#define current_buffer (this->hidden->current_buffer)
#define playing (this->hidden->playing)
#endif /* _SDL_ahiaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -27,7 +27,6 @@
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_artsaudio.h"
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
......@@ -40,19 +39,12 @@
/* The tag name used by artsc audio */
#define ARTS_DRIVER_NAME "arts"
/* Audio driver functions */
static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void ARTS_WaitAudio(_THIS);
static void ARTS_PlayAudio(_THIS);
static Uint8 *ARTS_GetAudioBuf(_THIS);
static void ARTS_CloseAudio(_THIS);
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
static void *arts_handle = NULL;
static int arts_loaded = 0;
/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
static int (*SDL_NAME(arts_init)) (void);
static void (*SDL_NAME(arts_free)) (void);
static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
......@@ -65,28 +57,32 @@ static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
int count);
static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} arts_functions[] = {
{
"arts_init", (void **) &SDL_NAME(arts_init)}, {
"arts_free", (void **) &SDL_NAME(arts_free)}, {
"arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, {
"arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, {
"arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, {
"arts_write", (void **) &SDL_NAME(arts_write)}, {
"arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},};
SDL_ARTS_SYM(arts_init),
SDL_ARTS_SYM(arts_free),
SDL_ARTS_SYM(arts_play_stream),
SDL_ARTS_SYM(arts_stream_set),
SDL_ARTS_SYM(arts_stream_get),
SDL_ARTS_SYM(arts_write),
SDL_ARTS_SYM(arts_close_stream),
SDL_ARTS_SYM(arts_error_text),
};
#undef SDL_ARTS_SYM
static void
UnloadARTSLibrary()
{
if (arts_loaded) {
if (arts_handle != NULL) {
SDL_UnloadObject(arts_handle);
arts_handle = NULL;
arts_loaded = 0;
}
}
......@@ -95,20 +91,22 @@ LoadARTSLibrary(void)
{
int i, retval = -1;
arts_handle = SDL_LoadObject(arts_library);
if (arts_handle) {
arts_loaded = 1;
retval = 0;
for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
*arts_functions[i].func =
SDL_LoadFunction(arts_handle, arts_functions[i].name);
if (!*arts_functions[i].func) {
retval = -1;
UnloadARTSLibrary();
break;
if (arts_handle == NULL) {
arts_handle = SDL_LoadObject(arts_library);
if (arts_handle != NULL) {
retval = 0;
for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
*arts_functions[i].func =
SDL_LoadFunction(arts_handle, arts_functions[i].name);
if (!*arts_functions[i].func) {
retval = -1;
UnloadARTSLibrary();
break;
}
}
}
}
return retval;
}
......@@ -128,117 +126,45 @@ LoadARTSLibrary(void)
#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int available = 0;
if (LoadARTSLibrary() < 0) {
return available;
}
if (SDL_NAME(arts_init) () == 0) {
#define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */
#ifdef ARTS_CRASH_HACK
arts_stream_t stream2;
stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
SDL_NAME(arts_write) (stream2, "", 0);
SDL_NAME(arts_close_stream) (stream2);
#endif
available = 1;
SDL_NAME(arts_free) ();
}
UnloadARTSLibrary();
return available;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadARTSLibrary();
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadARTSLibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
stream = 0;
/* Set the function pointers */
this->OpenAudio = ARTS_OpenAudio;
this->WaitAudio = ARTS_WaitAudio;
this->PlayAudio = ARTS_PlayAudio;
this->GetAudioBuf = ARTS_GetAudioBuf;
this->CloseAudio = ARTS_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ARTS_bootstrap = {
ARTS_DRIVER_NAME, "Analog Realtime Synthesizer",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
ARTS_WaitAudio(_THIS)
ARTS_WaitDevice(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}
static void
ARTS_PlayAudio(_THIS)
ARTS_PlayDevice(_THIS)
{
int written;
/* Write the audio data */
written = SDL_NAME(arts_write) (stream, mixbuf, mixlen);
int written = SDL_NAME(arts_write) (
this->hidden->stream,
this->hidden->mixbuf,
this->hidden->mixlen);
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
......@@ -250,41 +176,57 @@ ARTS_PlayAudio(_THIS)
#endif
}
static void
ARTS_WaitDone(_THIS)
{
/* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
}
static Uint8 *
ARTS_GetAudioBuf(_THIS)
ARTS_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}
static void
ARTS_CloseAudio(_THIS)
ARTS_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (stream) {
SDL_NAME(arts_close_stream) (stream);
stream = 0;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->stream) {
SDL_NAME(arts_close_stream) (this->hidden->stream);
this->hidden->stream = 0;
}
SDL_NAME(arts_free) ();
SDL_free(this->hidden);
this->hidden = NULL;
}
SDL_NAME(arts_free) ();
}
static int
ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec)
ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
{
int bits, frag_spec;
SDL_AudioFormat test_format, format;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
int rc = 0;
int bits = 0, frag_spec = 0;
SDL_AudioFormat test_format = 0, format = 0;
mixbuf = NULL;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Try for a closest match on audio format */
format = 0;
bits = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
......@@ -307,51 +249,108 @@ ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
}
if (format == 0) {
ARTS_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return (-1);
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
if (SDL_NAME(arts_init) () != 0) {
SDL_SetError("Unable to initialize ARTS");
return (-1);
if ((rc = SDL_NAME(arts_init) ()) != 0) {
ARTS_CloseDevice(this);
SDL_SetError( "Unable to initialize ARTS: %s",
SDL_NAME(arts_error_text)(rc) );
return 0;
}
stream =
SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL");
this->hidden->stream = SDL_NAME(arts_play_stream) (
this->spec.freq,
bits, this->spec.channels,
"SDL");
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec);
if ((0x01 << frag_spec) != spec->size) {
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != this->spec.size) {
ARTS_CloseDevice(this);
SDL_SetError("Fragment size must be a power of two");
return (-1);
return 0;
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
#ifdef ARTS_P_PACKET_SETTINGS
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec);
SDL_NAME(arts_stream_set) (this->hidden->stream,
ARTS_P_PACKET_SETTINGS, frag_spec);
#else
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE,
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
frag_spec & 0xffff);
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16);
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
frag_spec >> 16);
#endif
spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE);
this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
ARTS_P_PACKET_SIZE);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ARTS_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static void
ARTS_Deinitialize(void)
{
UnloadARTSLibrary();
}
static int
ARTS_Init(SDL_AudioDriverImpl *impl)
{
if (LoadARTSLibrary() < 0) {
return 0;
} else {
if (SDL_NAME(arts_init) () != 0) {
UnloadARTSLibrary();
SDL_SetError("ARTS: arts_init failed (no audio server?)");
return 0;
}
/* Play a stream so aRts doesn't crash */
arts_stream_t stream;
stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
SDL_NAME(arts_write) (stream, "", 0);
SDL_NAME(arts_close_stream) (stream);
SDL_NAME(arts_free) ();
}
/* Set the function pointers */
impl->OpenDevice = ARTS_OpenDevice;
impl->PlayDevice = ARTS_PlayDevice;
impl->WaitDevice = ARTS_WaitDevice;
impl->GetDeviceBuf = ARTS_GetDeviceBuf;
impl->CloseDevice = ARTS_CloseDevice;
impl->WaitDone = ARTS_WaitDone;
impl->Deinitialize = ARTS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
AudioBootStrap ARTS_bootstrap = {
ARTS_DRIVER_NAME, "Analog RealTime Synthesizer", ARTS_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -28,7 +28,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -49,13 +49,5 @@ struct SDL_PrivateAudioData
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define stream (this->hidden->stream)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_artscaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -36,138 +36,81 @@ extern "C"
#include "../../thread/beos/SDL_systhread_c.h"
#include "SDL_beaudio.h"
}
/* Audio driver functions */
static int BE_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void BE_WaitAudio(_THIS);
static void BE_PlayAudio(_THIS);
static Uint8 *BE_GetAudioBuf(_THIS);
static void BE_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return (1);
}
static void Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *device;
/* Initialize all variables that we clean on shutdown */
device = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (device) {
SDL_memset(device, 0, (sizeof *device));
device->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *device->hidden));
}
if ((device == NULL) || (device->hidden == NULL)) {
SDL_OutOfMemory();
if (device) {
SDL_free(device);
}
return (0);
}
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
device->OpenAudio = BE_OpenAudio;
device->WaitAudio = BE_WaitAudio;
device->PlayAudio = BE_PlayAudio;
device->GetAudioBuf = BE_GetAudioBuf;
device->CloseAudio = BE_CloseAudio;
device->free = Audio_DeleteDevice;
/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
/* The BeOS callback for handling the audio buffer */
static void
FillSound(void *device, void *stream, size_t len,
const media_raw_audio_format & format)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
return device;
}
/* Silence the buffer, since it's ours */
SDL_memset(stream, audio->spec.silence, len);
AudioBootStrap BAUDIO_bootstrap = {
"baudio", "BeOS BSoundPlayer",
Audio_Available, Audio_CreateDevice
};
/* Only do soemthing if audio is enabled */
if (!audio->enabled)
return;
/* The BeOS callback for handling the audio buffer */
static void FillSound(void *device, void *stream, size_t len,
const media_raw_audio_format & format)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
/* Silence the buffer, since it's ours */
SDL_memset(stream, audio->spec.silence, len);
/* Only do soemthing if audio is enabled */
if (!audio->enabled)
return;
if (!audio->paused) {
if (audio->convert.needed) {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
if (!audio->paused) {
if (audio->convert.needed) {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
(Uint8 *) audio->convert.buf,
audio->convert.len);
SDL_mutexV(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream, audio->convert.buf,
audio->convert.len_cvt);
} else {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
(Uint8 *) stream, len);
SDL_mutexV(audio->mixer_lock);
}
SDL_mutexV(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
} else {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
(Uint8 *) stream, len);
SDL_mutexV(audio->mixer_lock);
}
return;
}
}
/* Dummy functions -- we don't use thread-based audio */
void BE_WaitAudio(_THIS)
{
return;
}
void BE_PlayAudio(_THIS)
{
return;
}
Uint8 *BE_GetAudioBuf(_THIS)
{
return (NULL);
}
void BE_CloseAudio(_THIS)
{
if (audio_obj) {
audio_obj->Stop();
delete audio_obj;
audio_obj = NULL;
static void
BEOSAUDIO_CloseDevice(_THIS)
{
if (_this->hidden != NULL) {
if (_this->hidden->audio_obj) {
_this->hidden->audio_obj->Stop();
delete _this->hidden->audio_obj;
_this->hidden->audio_obj = NULL;
}
/* Quit the Be Application, if there's nothing left to do */
SDL_QuitBeApp();
delete _this->hidden;
_this->hidden = NULL;
}
}
int BE_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
int valid_datatype = 0;
media_raw_audio_format format;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
/* Parse the audio format and fill the Be raw audio format */
memset(&format, '\0', sizeof(media_raw_audio_format));
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) spec->freq;
format.channel_count = spec->channels; /* !!! FIXME: support > 2? */
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
spec->format = test_format;
switch (test_format) {
static int
BEOSAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
{
int valid_datatype = 0;
media_raw_audio_format format;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
/* Initialize all variables that we clean on shutdown */
_this->hidden = new SDL_PrivateAudioData;
if (_this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
/* Parse the audio format and fill the Be raw audio format */
SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) _this->spec.freq;
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
_this->spec.format = test_format;
switch (test_format) {
case AUDIO_S8:
format.format = media_raw_audio_format::B_AUDIO_CHAR;
break;
......@@ -207,43 +150,67 @@ extern "C"
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
}
format.buffer_size = spec->samples;
format.buffer_size = _this->spec.samples;
if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format");
return (-1);
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
BEOSAUDIO_CloseDevice(_this);
SDL_SetError("Unsupported audio format");
return 0;
}
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return (-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
/* Subscribe to the audio stream (creates a new thread) */
sigset_t omask;
SDL_MaskSignals(&omask);
_this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
FillSound, NULL, _this);
SDL_UnmaskSignals(&omask);
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
_this->hidden->audio_obj->SetHasData(true);
} else {
BEOSAUDIO_CloseDevice(_this);
SDL_SetError("Unable to start Be audio");
return 0;
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* We're running! */
return 1;
}
/* Subscribe to the audio stream (creates a new thread) */
{
sigset_t omask;
SDL_MaskSignals(&omask);
audio_obj = new BSoundPlayer(&format, "SDL Audio", FillSound,
NULL, _this);
SDL_UnmaskSignals(&omask);
}
if (audio_obj->Start() == B_NO_ERROR) {
audio_obj->SetHasData(true);
} else {
SDL_SetError("Unable to start Be audio");
return (-1);
}
static void
BEOSAUDIO_Deinitialize(void)
{
SDL_QuitBeApp();
}
/* We're running! */
return (1);
static int
BEOSAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return 0;
}
}; /* Extern C */
/* Set the function pointers */
impl->OpenDevice = BEOSAUDIO_OpenDevice;
impl->CloseDevice = BEOSAUDIO_CloseDevice;
impl->Deinitialize = BEOSAUDIO_Deinitialize;
impl->ProvidesOwnCallbackThread = 1;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
extern "C" { extern AudioBootStrap BEOSAUDIO_bootstrap; }
AudioBootStrap BEOSAUDIO_bootstrap = {
"baudio", "BeOS BSoundPlayer", BEOSAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,12 +21,12 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_beaudio_h
#define _SDL_beaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData
......@@ -34,8 +34,6 @@ struct SDL_PrivateAudioData
BSoundPlayer *audio_obj;
};
/* Old variable names */
#define audio_obj (_this->hidden->audio_obj)
#endif /* _SDL_beaudio_h */
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -61,95 +61,152 @@
/* #define DEBUG_AUDIO_STREAM */
#ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS O_WRONLY
#define OPEN_FLAGS_OUTPUT O_WRONLY
#define OPEN_FLAGS_INPUT O_RDONLY
#else
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
#endif
/* Audio driver functions */
static void OBSD_WaitAudio(_THIS);
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void OBSD_PlayAudio(_THIS);
static Uint8 *OBSD_GetAudioBuf(_THIS);
static void OBSD_CloseAudio(_THIS);
/* !!! FIXME: so much cut and paste with dsp/dma drivers... */
static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
#ifdef DEBUG_AUDIO
static void OBSD_Status(_THIS);
#endif
static inline void
free_device_list(char ***devs, int *count)
{
SDL_FreeUnixAudioDevices(devs, count);
}
/* Audio driver bootstrap functions */
static inline void
build_device_list(int iscapture, char ***devs, int *count)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
}
static int
Audio_Available(void)
static inline void
build_device_lists(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
available = 1;
close(fd);
}
return (available);
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
static inline void
free_device_lists(void)
{
SDL_free(device->hidden);
SDL_free(device);
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static void
BSDAUDIO_Deinitialize(void)
{
SDL_AudioDevice *this;
free_device_lists();
}
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
static int
BSDAUDIO_DetectDevices(int iscapture)
{
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this)
SDL_free(this);
return (0);
return 0; /* shouldn't ever hit this. */
}
static const char *
BSDAUDIO_GetDeviceName(int index, int iscapture)
{
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index];
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index];
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = OBSD_OpenAudio;
this->WaitAudio = OBSD_WaitAudio;
this->PlayAudio = OBSD_PlayAudio;
this->GetAudioBuf = OBSD_GetAudioBuf;
this->CloseAudio = OBSD_CloseAudio;
SDL_SetError("No such device");
return NULL;
}
static void
BSDAUDIO_Status(_THIS)
{
#ifdef DEBUG_AUDIO
audio_info_t info;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
this->free = Audio_DeleteDevice;
fprintf(stderr, "\n"
"[play/record info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes" : "no");
return this;
fprintf(stderr, "\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
#endif /* DEBUG_AUDIO */
}
AudioBootStrap BSD_AUDIO_bootstrap = {
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
OBSD_WaitAudio(_THIS)
BSDAUDIO_WaitDevice(_THIS)
{
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
if (frame_ticks) {
if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
......@@ -159,13 +216,13 @@ OBSD_WaitAudio(_THIS)
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
FD_SET(this->hidden->audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) {
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
/* In general we should never print to the screen,
......@@ -175,7 +232,7 @@ OBSD_WaitAudio(_THIS)
fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
......@@ -188,13 +245,16 @@ OBSD_WaitAudio(_THIS)
}
static void
OBSD_PlayAudio(_THIS)
BSDAUDIO_PlayDevice(_THIS)
{
int written, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, &mixbuf[p], mixlen - p);
written = write(this->hidden->audio_fd,
&this->hidden->mixbuf[p],
this->hidden->mixlen - p);
if (written > 0)
p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
......@@ -211,8 +271,8 @@ OBSD_PlayAudio(_THIS)
while (p < written);
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
......@@ -225,141 +285,77 @@ OBSD_PlayAudio(_THIS)
}
static Uint8 *
OBSD_GetAudioBuf(_THIS)
BSDAUDIO_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}
static void
OBSD_CloseAudio(_THIS)
BSDAUDIO_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
#ifdef DEBUG_AUDIO
void
OBSD_Status(_THIS)
static int
BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
audio_info_t info;
if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
if ( ((iscapture) && (inputDeviceCount == 0)) ||
((!iscapture) && (outputDeviceCount == 0)) ) {
SDL_SetError("No such audio device");
return 0;
}
devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
}
fprintf(stderr, "\n"
"[play/record info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
info.
play.
buffer_size,
info.
play.
sample_rate,
info.
play.
channels,
info.
play.
precision,
info.
play.
encoding,
info.
play.
seek,
info.
play.
samples,
info.
play.
eof,
info.
play.
pause
?
"yes"
:
"no",
info.
play.
error
?
"yes"
:
"no",
info.
play.waiting ? "yes" : "no", info.play.active ? "yes" : "no");
fprintf(stderr, "\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
}
#endif /* DEBUG_AUDIO */
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
static int
OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
char audiodev[64];
SDL_AudioFormat format;
audio_info_t info;
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
}
AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
#ifdef USE_TIMER_SYNC
frame_ticks = 0.0;
#endif
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if (audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return (-1);
}
SDL_CalculateAudioSpec(&this->spec);
/* Set to play mode */
info.mode = AUMODE_PLAY;
if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
BSDAUDIO_CloseDevice(this);
SDL_SetError("Couldn't put device into play mode");
return (-1);
return 0;
}
mixbuf = NULL;
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(spec->format);
for (format = SDL_FirstAudioFormat(this->spec.format);
format; format = SDL_NextAudioFormat()) {
switch (format) {
case AUDIO_U8:
......@@ -389,46 +385,69 @@ OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
default:
continue;
}
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
break;
}
}
if (!format) {
SDL_SetError("No supported encoding for 0x%x", spec->format);
return (-1);
BSDAUDIO_CloseDevice(this);
SDL_SetError("No supported encoding for 0x%x", this->spec.format);
return 0;
}
spec->format = format;
this->spec.format = format;
AUDIO_INITINFO(&info);
info.play.channels = spec->channels;
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
spec->channels = 1;
info.play.channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
info.play.sample_rate = spec->freq;
info.blocksize = spec->size;
info.play.sample_rate = this->spec.freq;
info.blocksize = this->spec.size;
info.hiwat = 5;
info.lowat = 3;
(void) ioctl(audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(audio_fd, AUDIO_GETINFO, &info);
spec->freq = info.play.sample_rate;
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
this->spec.freq = info.play.sample_rate;
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
BSDAUDIO_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
#ifdef DEBUG_AUDIO
OBSD_Status(this);
#endif
BSDAUDIO_Status(this);
/* We're ready to rock and roll. :-) */
return (0);
}
static int
BSDAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = BSDAUDIO_DetectDevices;
impl->GetDeviceName = BSDAUDIO_GetDeviceName;
impl->OpenDevice = BSDAUDIO_OpenDevice;
impl->PlayDevice = BSDAUDIO_PlayDevice;
impl->WaitDevice = BSDAUDIO_WaitDevice;
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice;
impl->Deinitialize = BSDAUDIO_Deinitialize;
build_device_lists();
return 1;
}
AudioBootStrap BSD_AUDIO_bootstrap = {
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC, BSDAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,8 +21,8 @@
*/
#include "SDL_config.h"
#ifndef _SDL_openbsdaudio_h
#define _SDL_openbsdaudio_h
#ifndef _SDL_bsdaudio_h
#define _SDL_bsdaudio_h
#include "../SDL_sysaudio.h"
......@@ -47,13 +47,6 @@ struct SDL_PrivateAudioData
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_bsdaudio_h */
#endif /* _SDL_openbsdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -42,10 +42,10 @@ typedef struct _tMixBufferDesc
//---------------------------------------------------------------------
// DARTEventFunc
//
// This function is called by DART, when an event occures, like end of
// This function is called by DART, when an event occurs, like end of
// playback of a buffer, etc...
//---------------------------------------------------------------------
LONG APIENTRY
static LONG APIENTRY
DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
{
if (ulFlags && MIX_WRITE_COMPLETE) { // Playback of buffer completed!
......@@ -71,13 +71,12 @@ DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
}
int
DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
static int
DART_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
int valid_datatype = 0;
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
int iDeviceOrd = 0; // Default device to be used
int bOpenShared = 1; // Try opening it shared
int iBits = 16; // Default is 16 bits signed
......@@ -89,6 +88,15 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
int iSilence;
int rc;
/* Initialize all variables that we clean on shutdown */
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *_this->hidden));
if (_this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
// First thing is to try to open a given DART device!
SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
// pszDeviceType should contain the device type in low word, and device ordinal in high word!
......@@ -100,30 +108,34 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
iOpenMode |= MCI_OPEN_SHAREABLE;
rc = mciSendCommand(0, MCI_OPEN, iOpenMode, (PVOID) & AmpOpenParms, 0);
if (rc != MCIERR_SUCCESS) // No audio available??
return (-1);
if (rc != MCIERR_SUCCESS) { // No audio available??
DART_CloseDevice(_this);
SDL_SetError("DART: Couldn't open audio device.");
return 0;
}
// Save the device ID we got from DART!
// We will use this in the next calls!
iDeviceOrd = AmpOpenParms.usDeviceID;
_this->hidden->iCurrDeviceOrd = iDeviceOrd = AmpOpenParms.usDeviceID;
// Determine the audio parameters from the AudioSpec
if (spec->channels > 2)
spec->channels = 2; // !!! FIXME: more than stereo support in OS/2?
if (_this->spec.channels > 4)
_this->spec.channels = 4;
while ((!valid_datatype) && (test_format)) {
spec->format = test_format;
_this->spec.format = test_format;
valid_datatype = 1;
switch (test_format) {
case AUDIO_U8:
// Unsigned 8 bit audio data
iSilence = 0x80;
iBits = 8;
_this->hidden->iCurrBits = iBits = 8;
break;
case AUDIO_S16LSB:
// Signed 16 bit audio data
iSilence = 0x00;
iBits = 16;
_this->hidden->iCurrBits = iBits = 16;
break;
// !!! FIXME: int32?
......@@ -137,16 +149,16 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (!valid_datatype) { // shouldn't happen, but just in case...
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("Unsupported audio format");
return (-1);
return 0;
}
iFreq = spec->freq;
iChannels = spec->channels;
_this->hidden->iCurrFreq = iFreq = _this->spec.freq;
_this->hidden->iCurrChannels = iChannels = _this->spec.channels;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
iBufSize = spec->size;
SDL_CalculateAudioSpec(&_this->spec);
_this->hidden->iCurrBufSize = iBufSize = _this->spec.size;
// Now query this device if it supports the given freq/bits/channels!
SDL_memset(&(_this->hidden->MixSetupParms), 0,
......@@ -163,9 +175,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
&(_this->hidden->MixSetupParms), 0);
if (rc != MCIERR_SUCCESS) { // The device cannot handle this format!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("Audio device doesn't support requested audio format");
return (-1);
return 0;
}
// The device can handle this format, so initialize!
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
......@@ -173,9 +185,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
&(_this->hidden->MixSetupParms), 0);
if (rc != MCIERR_SUCCESS) { // The device could not be opened!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("Audio device could not be set up");
return (-1);
return 0;
}
// Ok, the device is initialized.
// Now we should allocate buffers. For this, we need a place where
......@@ -184,9 +196,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
(MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER) * iNumBufs);
if (!(_this->hidden->pMixBuffers)) { // Not enough memory!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Not enough memory for audio buffer descriptors");
return (-1);
DART_CloseDevice(_this);
SDL_OutOfMemory();
return 0;
}
// Now that we have the place for buffer list, we can ask DART for the
// buffers!
......@@ -201,12 +213,12 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|| (iNumBufs != _this->hidden->BufferParms.ulNumBuffers)
|| (_this->hidden->BufferParms.ulBufferSize == 0)) { // Could not allocate memory!
// Close DART, and exit with error code!
SDL_free(_this->hidden->pMixBuffers);
_this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("DART could not allocate buffers");
return (-1);
return 0;
}
_this->hidden->iCurrNumBufs = iNumBufs;
// Ok, we have all the buffers allocated, let's mark them!
{
int i;
......@@ -216,24 +228,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
// Check if this buffer was really allocated by DART
if ((!(_this->hidden->pMixBuffers[i].pBuffer))
|| (!pBufferDesc)) { // Wrong buffer!
// Close DART, and exit with error code!
// Free buffer descriptions
{
int j;
for (j = 0; j < i; j++)
SDL_free((void *) (_this->hidden->pMixBuffers[j].
ulUserParm));
}
// and cleanup
mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers);
_this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT,
&GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("Error at internal buffer check");
return (-1);
return 0;
}
pBufferDesc->iBufferUsage = BUFFER_EMPTY;
pBufferDesc->pSDLAudioDevice = _this;
......@@ -254,43 +251,41 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (DosCreateEventSem
(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE) != NO_ERROR)
{
// Could not create event semaphore!
{
int i;
for (i = 0; i < iNumBufs; i++)
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
}
mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers);
_this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
DART_CloseDevice(_this);
SDL_SetError("Could not create event semaphore");
return (-1);
return 0;
}
// Store the new settings in global variables
_this->hidden->iCurrDeviceOrd = iDeviceOrd;
_this->hidden->iCurrFreq = iFreq;
_this->hidden->iCurrBits = iBits;
_this->hidden->iCurrChannels = iChannels;
_this->hidden->iCurrNumBufs = iNumBufs;
_this->hidden->iCurrBufSize = iBufSize;
return (0);
return 1;
}
void
static void
DART_ThreadInit(_THIS)
{
return;
/* Increase the priority of this thread to make sure that
the audio will be continuous all the time! */
#ifdef USE_DOSSETPRIORITY
if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) {
#ifdef DEBUG_BUILD
printf
("[DART_ThreadInit] : Setting priority to TimeCritical+0! (TID%d)\n",
SDL_ThreadID());
#endif
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
} else {
#ifdef DEBUG_BUILD
printf
("[DART_ThreadInit] : Setting priority to ForegroundServer+0! (TID%d)\n",
SDL_ThreadID());
#endif
DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
}
#endif
}
/* This function waits until it is possible to write a full sound buffer */
void
DART_WaitAudio(_THIS)
static void
DART_WaitDevice(_THIS)
{
int i;
pMixBufferDesc pBufDesc;
......@@ -308,8 +303,8 @@ DART_WaitAudio(_THIS)
return;
}
void
DART_PlayAudio(_THIS)
static void
DART_PlayDevice(_THIS)
{
int iFreeBuf = _this->hidden->iNextFreeBuffer;
pMixBufferDesc pBufDesc;
......@@ -328,8 +323,8 @@ DART_PlayAudio(_THIS)
_this->hidden->iNextFreeBuffer = iFreeBuf;
}
Uint8 *
DART_GetAudioBuf(_THIS)
static Uint8 *
DART_GetDeviceBuf(_THIS)
{
int iFreeBuf;
Uint8 *pResult;
......@@ -348,125 +343,110 @@ DART_GetAudioBuf(_THIS)
return pResult;
}
} else
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n",
printf("[DART_GetDeviceBuf] : ERROR! pBufDesc = %p\n",
pBufDesc);
} else
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n",
printf("[DART_GetDeviceBuf] : ERROR! _this->hidden = %p\n",
_this->hidden);
} else
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
printf("[DART_GetDeviceBuf] : ERROR! _this = %p\n", _this);
return NULL;
}
void
static void
DART_WaitDone(_THIS)
{
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
APIRET rc;
ULONG ulPostCount = 0;
APIRET rc = NO_ERROR;
pBufDesc = (pMixBufferDesc)
_this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
pBufDesc =
(pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->
iLastPlayedBuf].
ulUserParm;
rc = NO_ERROR;
while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc == NO_ERROR)) {
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
}
}
void
DART_CloseAudio(_THIS)
static void
DART_CloseDevice(_THIS)
{
MCI_GENERIC_PARMS GenericParms;
int rc;
int i;
// Stop DART playback
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT,
&GenericParms, 0);
if (rc != MCIERR_SUCCESS) {
if (_this->hidden != NULL) {
// Stop DART playback
if (_this->hidden->iCurrDeviceOrd) {
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP,
MCI_WAIT, &GenericParms, 0);
#ifdef SFX_DEBUG_BUILD
printf("Could not stop DART playback!\n");
fflush(stdout);
if (rc != MCIERR_SUCCESS) {
printf("Could not stop DART playback!\n");
fflush(stdout);
}
#endif
}
// Close event semaphore
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
}
// Free memory of buffer descriptions
{
int i;
for (i = 0; i < _this->hidden->iCurrNumBufs; i++)
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
}
// Close event semaphore
if (_this->hidden->hevAudioBufferPlayed) {
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
_this->hidden->hevAudioBufferPlayed = 0;
}
// Deallocate buffers
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
// Free memory of buffer descriptions
for (i = 0; i < _this->hidden->iCurrNumBufs; i++) {
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
_this->hidden->pMixBuffers[i].ulUserParm = 0;
}
_this->hidden->iCurrNumBufs = 0;
// Free bufferlist
SDL_free(_this->hidden->pMixBuffers);
_this->hidden->pMixBuffers = NULL;
// Deallocate buffers
if (_this->hidden->iCurrDeviceOrd) {
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
}
// Close dart
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT,
&(GenericParms), 0);
}
// Free bufferlist
if (_this->hidden->pMixBuffers != NULL) {
SDL_free(_this->hidden->pMixBuffers);
_this->hidden->pMixBuffers = NULL;
}
/* Audio driver bootstrap functions */
// Close dart
if (_this->hidden->iCurrDeviceOrd) {
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE,
MCI_WAIT, &(GenericParms), 0);
}
_this->hidden->iCurrDeviceOrd = 0;
int
Audio_Available(void)
{
return (1);
SDL_free(_this->hidden);
_this->hidden = NULL;
}
}
void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static int
DART_Init(SDL_AudioDriverImpl *impl)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this)
SDL_free(this);
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DART_OpenAudio;
this->ThreadInit = DART_ThreadInit;
this->WaitAudio = DART_WaitAudio;
this->PlayAudio = DART_PlayAudio;
this->GetAudioBuf = DART_GetAudioBuf;
this->WaitDone = DART_WaitDone;
this->CloseAudio = DART_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
impl->OpenDevice = DART_OpenDevice;
impl->ThreadInit = DART_ThreadInit;
impl->WaitDevice = DART_WaitDevice;
impl->GetDeviceBuf = DART_GetDeviceBuf;
impl->PlayDevice = DART_PlayDevice;
impl->WaitDone = DART_WaitDone;
impl->CloseDevice = DART_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this right? */
return 1;
}
AudioBootStrap DART_bootstrap = {
"dart", "OS/2 Direct Audio RouTines (DART)",
Audio_Available, Audio_CreateDevice
"dart", "OS/2 Direct Audio RouTines (DART)", DART_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,14 +21,15 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_dart_h
#define _SDL_dart_h
#define INCL_TYPES
#define INCL_DOSSEMAPHORES
#define INCL_DOSRESOURCES
#define INCL_DOSMISC
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_OS2MM
#define INCL_MMIOOS2
......@@ -60,5 +61,6 @@ struct SDL_PrivateAudioData
HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART
};
#endif /* _SDL_lowaudio_h */
#endif /* _SDL_dart_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -28,85 +28,11 @@
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dcaudio.h"
#include "aica.h"
#include <dc/spu.h>
/* Audio driver functions */
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DCAUD_WaitAudio(_THIS);
static void DCAUD_PlayAudio(_THIS);
static Uint8 *DCAUD_GetAudioBuf(_THIS);
static void DCAUD_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
DCAUD_Available(void)
{
return 1;
}
static void
DCAUD_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
DCAUD_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DCAUD_OpenAudio;
this->WaitAudio = DCAUD_WaitAudio;
this->PlayAudio = DCAUD_PlayAudio;
this->GetAudioBuf = DCAUD_GetAudioBuf;
this->CloseAudio = DCAUD_CloseAudio;
this->free = DCAUD_DeleteDevice;
spu_init();
return this;
}
AudioBootStrap DCAUD_bootstrap = {
"dcaudio", "Dreamcast AICA audio",
DCAUD_Available, DCAUD_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
DCAUD_WaitAudio(_THIS)
{
if (this->hidden->playing) {
/* wait */
while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
thd_pass();
}
}
}
#define SPU_RAM_BASE 0xa0800000
static void
......@@ -152,7 +78,7 @@ spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size)
}
static void
DCAUD_PlayAudio(_THIS)
DCAUD_PlayDevice(_THIS)
{
SDL_AudioSpec *spec = &this->spec;
unsigned int offset;
......@@ -200,28 +126,59 @@ DCAUD_PlayAudio(_THIS)
}
static Uint8 *
DCAUD_GetAudioBuf(_THIS)
DCAUD_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
/* This function waits until it is possible to write a full sound buffer */
static void
DCAUD_CloseAudio(_THIS)
DCAUD_WaitDevice(_THIS)
{
aica_stop(0);
if (this->spec.channels == 2)
aica_stop(1);
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->playing) {
/* wait */
while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
thd_pass();
}
}
}
static void
DCAUD_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
aica_stop(0);
if (this->spec.channels == 2) {
aica_stop(1);
}
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
/* !!! FIXME: is there a reverse of spu_init()? */
}
}
static int
DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
DCAUD_OpenDevice(_THIS, SDL_AudioSpec * spec)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
spu_init();
while ((!valid_datatype) && (test_format)) {
spec->format = test_format;
switch (test_format) {
......@@ -238,8 +195,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
DCAUD_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return (-1);
return 0;
}
if (spec->channels > 2)
......@@ -252,7 +210,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return (-1);
DCAUD_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
this->hidden->leftpos = 0x11000;
......@@ -261,7 +221,25 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
this->hidden->nextbuf = 0;
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static int
DCAUD_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = DCAUD_OpenDevice;
impl->PlayDevice = DCAUD_PlayDevice;
impl->WaitDevice = DCAUD_WaitDevice;
impl->GetDeviceBuf = DCAUD_GetDeviceBuf;
impl->CloseDevice = DCAUD_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
AudioBootStrap DCAUD_bootstrap = {
"dcaudio", "Dreamcast AICA audio", DCAUD_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......
......@@ -34,7 +34,6 @@
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_diskaudio.h"
/* The tag name used by DISK audio */
......@@ -46,90 +45,27 @@
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150
/* Audio driver functions */
static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DISKAUD_WaitAudio(_THIS);
static void DISKAUD_PlayAudio(_THIS);
static Uint8 *DISKAUD_GetAudioBuf(_THIS);
static void DISKAUD_CloseAudio(_THIS);
static const char *
DISKAUD_GetOutputFilename(void)
{
const char *envr = SDL_getenv(DISKENVR_OUTFILE);
return ((envr != NULL) ? envr : DISKDEFAULT_OUTFILE);
}
/* Audio driver bootstrap functions */
static int
DISKAUD_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
if (envr && (SDL_strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
return (1);
}
return (0);
}
static void
DISKAUD_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
DISKAUD_CreateDevice(int devindex)
DISKAUD_GetOutputFilename(const char *devname)
{
SDL_AudioDevice *this;
const char *envr;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
if (devname == NULL) {
devname = SDL_getenv(DISKENVR_OUTFILE);
if (devname == NULL) {
devname = DISKDEFAULT_OUTFILE;
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
envr = SDL_getenv(DISKENVR_WRITEDELAY);
this->hidden->write_delay =
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
/* Set the function pointers */
this->OpenAudio = DISKAUD_OpenAudio;
this->WaitAudio = DISKAUD_WaitAudio;
this->PlayAudio = DISKAUD_PlayAudio;
this->GetAudioBuf = DISKAUD_GetAudioBuf;
this->CloseAudio = DISKAUD_CloseAudio;
this->free = DISKAUD_DeleteDevice;
return this;
return devname;
}
AudioBootStrap DISKAUD_bootstrap = {
DISKAUD_DRIVER_NAME, "direct-to-disk audio",
DISKAUD_Available, DISKAUD_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
DISKAUD_WaitAudio(_THIS)
DISKAUD_WaitDevice(_THIS)
{
SDL_Delay(this->hidden->write_delay);
}
static void
DISKAUD_PlayAudio(_THIS)
DISKAUD_PlayDevice(_THIS)
{
int written;
......@@ -147,49 +83,86 @@ DISKAUD_PlayAudio(_THIS)
}
static Uint8 *
DISKAUD_GetAudioBuf(_THIS)
DISKAUD_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
DISKAUD_CloseAudio(_THIS)
DISKAUD_CloseDevice(_THIS)
{
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->output != NULL) {
SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->output != NULL) {
SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture)
{
const char *fname = DISKAUD_GetOutputFilename();
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
const char *fname = DISKAUD_GetOutputFilename(devname);
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof (*this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, sizeof (*this->hidden));
/* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb");
if (this->hidden->output == NULL) {
return (-1);
DISKAUD_CloseDevice(this);
return 0;
}
#if HAVE_STDIO_H
fprintf(stderr, "WARNING: You are using the SDL disk writer"
" audio driver!\n Writing to file [%s].\n", fname);
#endif
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return (-1);
DISKAUD_CloseDevice(this);
return 0;
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
this->hidden->mixlen = this->spec.size;
this->hidden->write_delay =
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
#if HAVE_STDIO_H
fprintf(stderr,
"WARNING: You are using the SDL disk writer audio driver!\n"
" Writing to file [%s].\n", fname);
#endif
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static int
DISKAUD_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = DISKAUD_OpenDevice;
impl->WaitDevice = DISKAUD_WaitDevice;
impl->PlayDevice = DISKAUD_PlayDevice;
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
impl->CloseDevice = DISKAUD_CloseDevice;
return 1;
}
AudioBootStrap DISKAUD_bootstrap = {
DISKAUD_DRIVER_NAME, "direct-to-disk audio", DISKAUD_Init, 1
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -27,7 +27,7 @@
#include "SDL_rwops.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......
......@@ -21,6 +21,8 @@
*/
#include "SDL_config.h"
/* !!! FIXME: merge this driver with "dsp". */
/* Allow access to a raw mixing buffer */
#include <stdio.h>
......@@ -57,208 +59,100 @@
#define DMA_DRIVER_NAME "dma"
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_RDWR|O_NONBLOCK)
/* Audio driver functions */
static int DMA_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DMA_WaitAudio(_THIS);
static void DMA_PlayAudio(_THIS);
static Uint8 *DMA_GetAudioBuf(_THIS);
static void DMA_CloseAudio(_THIS);
#define OPEN_FLAGS_INPUT (O_RDWR|O_NONBLOCK)
#define OPEN_FLAGS_OUTPUT (O_RDWR|O_NONBLOCK)
/* Audio driver bootstrap functions */
static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
static int
Audio_Available(void)
test_for_mmap(int fd)
{
int available;
int fd;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
int caps;
struct audio_buf_info info;
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) {
available = 1;
int caps = 0;
struct audio_buf_info info;
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0))
{
size_t len = info.fragstotal * info.fragsize;
Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
if (buf != MAP_FAILED) {
munmap(buf, len);
return 1;
}
close(fd);
}
return (available);
return 0;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
static inline void
free_device_list(char ***devs, int *count)
{
SDL_free(device->hidden);
SDL_free(device);
SDL_FreeUnixAudioDevices(devs, count);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static inline void
build_device_list(int iscapture, char ***devs, int *count)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = DMA_OpenAudio;
this->WaitAudio = DMA_WaitAudio;
this->PlayAudio = DMA_PlayAudio;
this->GetAudioBuf = DMA_GetAudioBuf;
this->CloseAudio = DMA_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, test_for_mmap, devs, count);
}
AudioBootStrap DMA_bootstrap = {
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
DMA_WaitAudio(_THIS)
static inline void
build_device_lists(void)
{
fd_set fdset;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
this->enabled = 0;
}
}
}
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
/* See if we need to use timed audio synchronization */
if (frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
const char *message =
#ifdef AUDIO_OSPACE_HACK
"Audio timeout - buggy audio driver? (trying ospace)";
#else
"Audio timeout - buggy audio driver? (disabled)";
#endif
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
#ifdef AUDIO_OSPACE_HACK
/* We may be able to use GET_OSPACE trick */
frame_ticks = (float) (this->spec->samples * 1000) /
this->spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
#else
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
#endif /* AUDIO_OSPACE_HACK */
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
static inline void
free_device_lists(void)
{
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
}
static void
DMA_PlayAudio(_THIS)
static void DMA_Deinitialize(void)
{
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
}
return;
free_device_lists();
}
static Uint8 *
DMA_GetAudioBuf(_THIS)
static int
DMA_DetectDevices(int iscapture)
{
count_info info;
int playing;
int filling;
/* Get number of blocks, looping if we're not using select() */
do {
if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
/* Uh oh... */
this->enabled = 0;
return (NULL);
}
}
while (frame_ticks && (info.blocks < 1));
#ifdef DEBUG_AUDIO
if (info.blocks > 1) {
printf("Warning: audio underflow (%d frags)\n", info.blocks - 1);
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
}
#endif
playing = info.ptr / this->spec.size;
filling = (playing + 1) % num_buffers;
return (dma_buf + (filling * this->spec.size));
return 0; /* shouldn't ever hit this. */
}
static void
DMA_CloseAudio(_THIS)
static const char *
DMA_GetDeviceName(int index, int iscapture)
{
if (dma_buf != NULL) {
munmap(dma_buf, dma_len);
dma_buf = NULL;
}
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index];
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index];
}
SDL_SetError("No such device");
return NULL;
}
static int
DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
SDL_AudioSpec * spec)
DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo)
{
int frag_spec;
int value;
......@@ -272,11 +166,11 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec);
if ((0x01 << frag_spec) != spec->size) {
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != this->spec.size) {
SDL_SetError("Fragment size must be a power of two");
return (-1);
}
......@@ -295,7 +189,7 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
}
/* Set mono or stereo audio */
value = (spec->channels > 1);
value = (this->spec.channels > 1);
if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
(value != stereo)) {
SDL_SetError("Couldn't set audio channels");
......@@ -303,48 +197,86 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
}
/* Set the DSP frequency */
value = spec->freq;
value = this->spec.freq;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
SDL_SetError("Couldn't set audio frequency");
return (-1);
}
spec->freq = value;
this->spec.freq = value;
/* We successfully re-opened the audio */
return (0);
}
static void
DMA_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (dma_buf != NULL) {
munmap(dma_buf, dma_len);
dma_buf = NULL;
}
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
DMA_OpenDevice(_THIS, const char *devname, int iscapture)
{
char audiodev[1024];
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format;
int stereo;
int value;
SDL_AudioFormat test_format;
struct audio_buf_info info;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
if ( ((iscapture) && (inputDeviceCount == 0)) ||
((!iscapture) && (outputDeviceCount == 0)) ) {
SDL_SetError("No such audio device");
return 0;
}
devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
audio_fd = open(devname, flags, 0);
if (audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return (-1);
DMA_CloseDevice(this);
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
}
dma_buf = NULL;
ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
/* Get a list of supported hardware formats */
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't get audio format list");
return (-1);
return 0;
}
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
......@@ -389,61 +321,66 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
}
if (format == 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return (-1);
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
/* Set the audio format */
value = format;
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't set audio format");
return (-1);
return 0;
}
/* Set mono or stereo audio (currently only two channels supported) */
stereo = (spec->channels > 1);
stereo = (this->spec.channels > 1);
ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
if (stereo) {
spec->channels = 2;
this->spec.channels = 2;
} else {
spec->channels = 1;
this->spec.channels = 1;
}
/* Because some drivers don't allow setting the buffer size
after setting the format, we must re-open the audio device
once we know what format and channels are supported
*/
if (DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0) {
if (DMA_ReopenAudio(this, devname, format, stereo) < 0) {
DMA_CloseDevice(this);
/* Error is set by DMA_ReopenAudio() */
return (-1);
return 0;
}
/* Memory map the audio buffer */
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't get OSPACE parameters");
return (-1);
return 0;
}
spec->size = info.fragsize;
spec->samples = spec->size / ((spec->format & 0xFF) / 8);
spec->samples /= spec->channels;
this->spec.size = info.fragsize;
this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8);
this->spec.samples /= this->spec.channels;
num_buffers = info.fragstotal;
dma_len = num_buffers * spec->size;
dma_len = num_buffers * this->spec.size;
dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
audio_fd, 0);
if (dma_buf == MAP_FAILED) {
DMA_CloseDevice(this);
SDL_SetError("DMA memory map failed");
dma_buf = NULL;
return (-1);
return 0;
}
SDL_memset(dma_buf, spec->silence, dma_len);
SDL_memset(dma_buf, this->spec.silence, dma_len);
/* Check to see if we need to use select() workaround */
{
char *workaround;
workaround = SDL_getenv("SDL_DSP_NOSELECT");
if (workaround) {
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
next_frame = SDL_GetTicks() + frame_ticks;
}
}
......@@ -453,15 +390,145 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
value = PCM_ENABLE_OUTPUT;
if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't trigger audio output");
return (-1);
return 0;
}
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
/* This function waits until it is possible to write a full sound buffer */
static void
DMA_WaitDevice(_THIS)
{
fd_set fdset;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
this->enabled = 0;
}
}
}
/* See if we need to use timed audio synchronization */
if (frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
const char *message =
#ifdef AUDIO_OSPACE_HACK
"Audio timeout - buggy audio driver? (trying ospace)";
#else
"Audio timeout - buggy audio driver? (disabled)";
#endif
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
#ifdef AUDIO_OSPACE_HACK
/* We may be able to use GET_OSPACE trick */
frame_ticks = (float) (this->spec.samples * 1000) /
this->spec.freq;
next_frame = SDL_GetTicks() + frame_ticks;
#else
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
#endif /* AUDIO_OSPACE_HACK */
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
}
static void
DMA_PlayDevice(_THIS)
{
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
}
return;
}
static Uint8 *
DMA_GetDeviceBuf(_THIS)
{
count_info info;
int playing;
int filling;
/* Get number of blocks, looping if we're not using select() */
do {
if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
/* Uh oh... */
this->enabled = 0;
return (NULL);
}
}
while (frame_ticks && (info.blocks < 1));
#ifdef DEBUG_AUDIO
if (info.blocks > 1) {
printf("Warning: audio underflow (%d frags)\n", info.blocks - 1);
}
#endif
playing = info.ptr / this->spec.size;
filling = (playing + 1) % num_buffers;
return (dma_buf + (filling * this->spec.size));
}
static int
DMA_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = DMA_DetectDevices;
impl->GetDeviceName = DMA_GetDeviceName;
impl->OpenDevice = DMA_OpenDevice;
impl->WaitDevice = DMA_WaitDevice;
impl->PlayDevice = DMA_PlayDevice;
impl->GetDeviceBuf = DMA_GetDeviceBuf;
impl->CloseDevice = DMA_CloseDevice;
impl->Deinitialize = DMA_Deinitialize;
build_device_lists();
return 1;
}
AudioBootStrap DMA_bootstrap = {
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", DMA_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,12 +21,12 @@
*/
#include "SDL_config.h"
#ifndef _SDL_dspaudio_h
#define _SDL_dspaudio_h
#ifndef _SDL_dmaaudio_h
#define _SDL_dmaaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -49,6 +49,7 @@ struct SDL_PrivateAudioData
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
/* !!! FIXME: remove these. */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define dma_buf (this->hidden->dma_buf)
......@@ -57,5 +58,6 @@ struct SDL_PrivateAudioData
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_dspaudio_h */
#endif /* _SDL_dmaaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -45,73 +45,12 @@
#define alSetWidth(x,y) ALsetwidth(x,y)
#endif
/* Audio driver functions */
static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void AL_WaitAudio(_THIS);
static void AL_PlayAudio(_THIS);
static Uint8 *AL_GetAudioBuf(_THIS);
static void AL_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
return 1;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = AL_OpenAudio;
this->WaitAudio = AL_WaitAudio;
this->PlayAudio = AL_PlayAudio;
this->GetAudioBuf = AL_GetAudioBuf;
this->CloseAudio = AL_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DMEDIA_bootstrap = {
"AL", "IRIX DMedia audio",
Audio_Available, Audio_CreateDevice
};
void static
AL_WaitAudio(_THIS)
IRIXAUDIO_WaitDevice(_THIS)
{
Sint32 timeleft;
timeleft = this->spec.samples - alGetFillable(audio_port);
timeleft = this->spec.samples - alGetFillable(this->hidden->audio_port);
if (timeleft > 0) {
timeleft /= (this->spec.freq / 1000);
SDL_Delay((Uint32) timeleft);
......@@ -119,61 +58,78 @@ AL_WaitAudio(_THIS)
}
static void
AL_PlayAudio(_THIS)
IRIXAUDIO_PlayDevice(_THIS)
{
/* Write the audio data out */
if (alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0) {
ALport port = this->hidden->audio_port;
Uint8 *mixbuf = this->hidden->mixbuf;
if (alWriteFrames(port, mixbuf, this->spec.samples) < 0) {
/* Assume fatal error, for now */
this->enabled = 0;
}
}
static Uint8 *
AL_GetAudioBuf(_THIS)
IRIXAUDIO_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}
static void
AL_CloseAudio(_THIS)
IRIXAUDIO_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_port != NULL) {
alClosePort(audio_port);
audio_port = NULL;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_port != NULL) {
alClosePort(this->hidden->audio_port);
this->hidden->audio_port = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
IRIXAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
long width = 0;
long fmt = 0;
int valid = 0;
/* !!! FIXME: Handle multiple devices and capture? */
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
#ifdef OLD_IRIX_AUDIO
{
long audio_param[2];
audio_param[0] = AL_OUTPUT_RATE;
audio_param[1] = spec->freq;
audio_param[1] = this->spec.freq;
valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
}
#else
{
ALpv audio_param;
audio_param.param = AL_RATE;
audio_param.value.i = spec->freq;
audio_param.value.i = this->spec.freq;
valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
}
#endif
while ((!valid) && (test_format)) {
valid = 1;
spec->format = test_format;
this->spec.format = test_format;
switch (test_format) {
case AUDIO_S8:
......@@ -203,30 +159,31 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
ALconfig audio_config = alNewConfig();
valid = 0;
if (audio_config) {
if (alSetChannels(audio_config, spec->channels) < 0) {
if (spec->channels > 2) { /* can't handle > stereo? */
spec->channels = 2; /* try again below. */
if (alSetChannels(audio_config, this->spec.channels) < 0) {
if (this->spec.channels > 2) { /* can't handle > stereo? */
this->spec.channels = 2; /* try again below. */
}
}
if ((alSetSampFmt(audio_config, fmt) >= 0) &&
((!width) || (alSetWidth(audio_config, width) >= 0)) &&
(alSetQueueSize(audio_config, spec->samples * 2) >= 0) &&
(alSetChannels(audio_config, spec->channels) >= 0)) {
(alSetQueueSize(audio_config,this->spec.samples*2) >= 0) &&
(alSetChannels(audio_config, this->spec.channels) >= 0)) {
audio_port = alOpenPort("SDL audio", "w", audio_config);
if (audio_port == NULL) {
this->hidden->audio_port = alOpenPort("SDL audio", "w",
audio_config);
if (this->hidden->audio_port == NULL) {
/* docs say AL_BAD_CHANNELS happens here, too. */
int err = oserror();
if (err == AL_BAD_CHANNELS) {
spec->channels = 2;
alSetChannels(audio_config, spec->channels);
audio_port = alOpenPort("SDL audio", "w",
audio_config);
this->spec.channels = 2;
alSetChannels(audio_config, this->spec.channels);
this->hidden->audio_port = alOpenPort("SDL audio", "w",
audio_config);
}
}
if (audio_port != NULL) {
if (this->hidden->audio_port != NULL) {
valid = 1;
}
}
......@@ -237,23 +194,43 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
if (!valid) {
IRIXAUDIO_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return (-1);
return 0;
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size);
if (mixbuf == NULL) {
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
if (this->hidden->mixbuf == NULL) {
IRIXAUDIO_CloseDevice(this);
SDL_OutOfMemory();
return (-1);
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static int
IRIXAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->WaitDevice = DSP_WaitDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: not true, I think. */
return 1;
}
AudioBootStrap IRIXAUDIO_bootstrap = {
"AL", "IRIX DMedia audio", IRIXAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,8 +21,8 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_irixaudio_h
#define _SDL_irixaudio_h
#include <dmedia/audio.h>
......@@ -33,15 +33,10 @@
struct SDL_PrivateAudioData
{
/* The handle for the audio device */
ALport audio_port;
Uint8 *mixbuf; /* The app mixing buffer */
ALport audio_port; /* The handle for the audio device */
Uint8 *mixbuf; /* The app mixing buffer */
};
/* Old variable names */
#define audio_port (this->hidden->audio_port)
#define mixbuf (this->hidden->mixbuf)
#endif /* _SDL_irixaudio_h */
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -55,156 +55,158 @@
#define DSP_DRIVER_NAME "dsp"
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
/* Audio driver functions */
static int DSP_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DSP_WaitAudio(_THIS);
static void DSP_PlayAudio(_THIS);
static Uint8 *DSP_GetAudioBuf(_THIS);
static void DSP_CloseAudio(_THIS);
static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
static inline void
free_device_list(char ***devs, int *count)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
available = 1;
close(fd);
}
return (available);
SDL_FreeUnixAudioDevices(devs, count);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
static inline void
build_device_list(int iscapture, char ***devs, int *count)
{
SDL_free(device->hidden);
SDL_free(device);
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static inline void
build_device_lists(void)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = DSP_OpenAudio;
this->WaitAudio = DSP_WaitAudio;
this->PlayAudio = DSP_PlayAudio;
this->GetAudioBuf = DSP_GetAudioBuf;
this->CloseAudio = DSP_CloseAudio;
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
this->free = Audio_DeleteDevice;
return this;
static inline void
free_device_lists(void)
{
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
}
AudioBootStrap DSP_bootstrap = {
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
DSP_WaitAudio(_THIS)
DSP_Deinitialize(void)
{
/* Not needed at all since OSS handles waiting automagically */
free_device_lists();
}
static void
DSP_PlayAudio(_THIS)
static int
DSP_DetectDevices(int iscapture)
{
if (write(audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write");
this->enabled = 0;
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
return 0; /* shouldn't ever hit this. */
}
static Uint8 *
DSP_GetAudioBuf(_THIS)
static const char *
DSP_GetDeviceName(int index, int iscapture)
{
return (mixbuf);
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index];
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index];
}
SDL_SetError("No such device");
return NULL;
}
static void
DSP_CloseAudio(_THIS)
DSP_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
DSP_OpenDevice(_THIS, const char *devname, int iscapture)
{
char audiodev[1024];
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format;
int value;
int frag_spec;
SDL_AudioFormat test_format;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
if ( ((iscapture) && (inputDeviceCount == 0)) ||
((!iscapture) && (outputDeviceCount == 0)) ) {
SDL_SetError("No such audio device");
return 0;
}
devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if (audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return (-1);
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
}
mixbuf = NULL;
this->hidden->mixbuf = NULL;
/* Make the file descriptor use blocking writes with fcntl() */
{
long flags;
flags = fcntl(audio_fd, F_GETFL);
flags &= ~O_NONBLOCK;
if (fcntl(audio_fd, F_SETFL, flags) < 0) {
long ctlflags;
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
ctlflags &= ~O_NONBLOCK;
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio blocking mode");
DSP_CloseAudio(this);
return (-1);
return 0;
}
}
/* Get a list of supported hardware formats */
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
perror("SNDCTL_DSP_GETFMTS");
DSP_CloseDevice(this);
SDL_SetError("Couldn't get audio format list");
DSP_CloseAudio(this);
return (-1);
return 0;
}
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
......@@ -255,50 +257,51 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
}
if (format == 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
DSP_CloseAudio(this);
return (-1);
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
/* Set the audio format */
value = format;
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
if ( (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format) ) {
perror("SNDCTL_DSP_SETFMT");
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio format");
DSP_CloseAudio(this);
return (-1);
return 0;
}
/* Set the number of channels of output */
value = spec->channels;
if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
value = this->spec.channels;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
perror("SNDCTL_DSP_CHANNELS");
DSP_CloseDevice(this);
SDL_SetError("Cannot set the number of channels");
DSP_CloseAudio(this);
return (-1);
return 0;
}
spec->channels = value;
this->spec.channels = value;
/* Set the DSP frequency */
value = spec->freq;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
value = this->spec.freq;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
perror("SNDCTL_DSP_SPEED");
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio frequency");
DSP_CloseAudio(this);
return (-1);
return 0;
}
spec->freq = value;
this->spec.freq = value;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec);
if ((0x01U << frag_spec) != spec->size) {
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != this->spec.size) {
DSP_CloseDevice(this);
SDL_SetError("Fragment size must be a power of two");
DSP_CloseAudio(this);
return (-1);
return 0;
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
......@@ -307,13 +310,13 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
#endif
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#ifdef DEBUG_AUDIO
{
audio_buf_info info;
ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
fprintf(stderr, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize);
......@@ -322,19 +325,59 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
#endif
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
DSP_CloseAudio(this);
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DSP_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static void
DSP_PlayDevice(_THIS)
{
const Uint8 *mixbuf = this->hidden->mixbuf;
const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write");
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
}
static Uint8 *
DSP_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static int
DSP_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->GetDeviceName = DSP_GetDeviceName;
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->Deinitialize = DSP_Deinitialize;
build_device_lists();
return 1;
}
AudioBootStrap DSP_bootstrap = {
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", DSP_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -34,22 +34,11 @@ struct SDL_PrivateAudioData
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_dspaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -25,141 +25,27 @@
/* Output audio to nowhere... */
#include "SDL_rwops.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dummyaudio.h"
/* The tag name used by DUMMY audio */
#define DUMMYAUD_DRIVER_NAME "dummy"
/* Audio driver functions */
static int DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DUMMYAUD_WaitAudio(_THIS);
static void DUMMYAUD_PlayAudio(_THIS);
static Uint8 *DUMMYAUD_GetAudioBuf(_THIS);
static void DUMMYAUD_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
DUMMYAUD_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
if (envr && (SDL_strcmp(envr, DUMMYAUD_DRIVER_NAME) == 0)) {
return (1);
}
return (0);
}
static void
DUMMYAUD_DeleteDevice(SDL_AudioDevice * device)
DUMMYAUD_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_free(device->hidden);
SDL_free(device);
return 1; /* always succeeds. */
}
static SDL_AudioDevice *
DUMMYAUD_CreateDevice(int devindex)
static int
DUMMYAUD_Init(SDL_AudioDriverImpl *impl)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DUMMYAUD_OpenAudio;
this->WaitAudio = DUMMYAUD_WaitAudio;
this->PlayAudio = DUMMYAUD_PlayAudio;
this->GetAudioBuf = DUMMYAUD_GetAudioBuf;
this->CloseAudio = DUMMYAUD_CloseAudio;
this->free = DUMMYAUD_DeleteDevice;
return this;
impl->OpenDevice = DUMMYAUD_OpenDevice;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
AudioBootStrap DUMMYAUD_bootstrap = {
DUMMYAUD_DRIVER_NAME, "SDL dummy audio driver",
DUMMYAUD_Available, DUMMYAUD_CreateDevice
"dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
};
/* This function waits until it is possible to write a full sound buffer */
static void
DUMMYAUD_WaitAudio(_THIS)
{
/* Don't block on first calls to simulate initial fragment filling. */
if (this->hidden->initial_calls)
this->hidden->initial_calls--;
else
SDL_Delay(this->hidden->write_delay);
}
static void
DUMMYAUD_PlayAudio(_THIS)
{
/* no-op...this is a null driver. */
}
static Uint8 *
DUMMYAUD_GetAudioBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
DUMMYAUD_CloseAudio(_THIS)
{
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
}
static int
DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
float bytes_per_sec = 0.0f;
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return (-1);
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
bytes_per_sec = (float) (((spec->format & 0xFF) / 8) *
spec->channels * spec->freq);
/*
* We try to make this request more audio at the correct rate for
* a given audio spec, so timing stays fairly faithful.
* Also, we have it not block at all for the first two calls, so
* it seems like we're filling two audio fragments right out of the
* gate, like other SDL drivers tend to do.
*/
this->hidden->initial_calls = 2;
this->hidden->write_delay =
(Uint32) ((((float) spec->size) / bytes_per_sec) * 1000.0f);
/* We're ready to rock and roll. :-) */
return (0);
}
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......
......@@ -33,7 +33,6 @@
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_esdaudio.h"
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
......@@ -46,40 +45,34 @@
/* The tag name used by ESD audio */
#define ESD_DRIVER_NAME "esd"
/* Audio driver functions */
static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void ESD_WaitAudio(_THIS);
static void ESD_PlayAudio(_THIS);
static Uint8 *ESD_GetAudioBuf(_THIS);
static void ESD_CloseAudio(_THIS);
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
static void *esd_handle = NULL;
static int esd_loaded = 0;
static int (*SDL_NAME(esd_open_sound)) (const char *host);
static int (*SDL_NAME(esd_close)) (int esd);
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
const char *host, const char *name);
#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} esd_functions[] = {
{
"esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, {
"esd_close", (void **) &SDL_NAME(esd_close)}, {
"esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},};
SDL_ESD_SYM(esd_open_sound),
SDL_ESD_SYM(esd_close),
SDL_ESD_SYM(esd_play_stream),
};
#undef SDL_ESD_SYM
static void
UnloadESDLibrary()
{
if (esd_loaded) {
if (esd_handle != NULL) {
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
esd_loaded = 0;
}
}
......@@ -88,17 +81,18 @@ LoadESDLibrary(void)
{
int i, retval = -1;
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
esd_loaded = 1;
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
if (esd_handle == NULL) {
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
}
}
}
}
......@@ -121,78 +115,10 @@ LoadESDLibrary(void)
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int connection;
int available;
available = 0;
if (LoadESDLibrary() < 0) {
return available;
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection >= 0) {
available = 1;
SDL_NAME(esd_close) (connection);
}
UnloadESDLibrary();
return (available);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadESDLibrary();
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadESDLibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = ESD_OpenAudio;
this->WaitAudio = ESD_WaitAudio;
this->PlayAudio = ESD_PlayAudio;
this->GetAudioBuf = ESD_GetAudioBuf;
this->CloseAudio = ESD_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ESD_bootstrap = {
ESD_DRIVER_NAME, "Enlightened Sound Daemon",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
ESD_WaitAudio(_THIS)
ESD_WaitDevice(_THIS)
{
Sint32 ticks;
......@@ -202,28 +128,31 @@ ESD_WaitAudio(_THIS)
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}
static void
ESD_PlayAudio(_THIS)
ESD_PlayDevice(_THIS)
{
int written;
int written = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
written = write(this->hidden->audio_fd,
this->hidden->mixbuf,
this->hidden->mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
......@@ -232,7 +161,7 @@ ESD_PlayAudio(_THIS)
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* Set the next write frame */
next_frame += frame_ticks;
this->hidden->next_frame += this->hidden->frame_ticks;
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
......@@ -241,21 +170,26 @@ ESD_PlayAudio(_THIS)
}
static Uint8 *
ESD_GetAudioBuf(_THIS)
ESD_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}
static void
ESD_CloseAudio(_THIS)
ESD_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
SDL_NAME(esd_close) (audio_fd);
audio_fd = -1;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
......@@ -285,59 +219,135 @@ get_progname(void)
return (progname);
}
static int
ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
ESD_OpenDevice(_THIS, const char *devname, int iscapture)
{
esd_format_t format;
esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0;
int found = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->audio_fd = -1;
/* Convert audio spec to the ESD audio format */
format = (ESD_STREAM | ESD_PLAY);
switch (spec->format & 0xFF) {
case 8:
format |= ESD_BITS8;
break;
case 16:
format |= ESD_BITS16;
break;
default:
SDL_SetError("Unsupported ESD audio format");
return (-1);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!found && test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
found = 1;
switch (test_format) {
case AUDIO_U8:
format |= ESD_BITS8;
break;
case AUDIO_S16SYS:
format |= ESD_BITS16;
break;
default:
found = 0;
break;
}
}
if (spec->channels == 1) {
if (!found) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return 0;
}
if (this->spec.channels == 1) {
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
#if 0
spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
#endif
/* Open a connection to the ESD audio server */
audio_fd =
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
if (audio_fd < 0) {
this->hidden->audio_fd =
SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname());
if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't open ESD connection");
return (-1);
return 0;
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
SDL_CalculateAudioSpec(&this->spec);
this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ESD_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static void
ESD_Deinitialize(void)
{
UnloadESDLibrary();
}
static int
ESD_Init(SDL_AudioDriverImpl *impl)
{
if (LoadESDLibrary() < 0) {
return 0;
} else {
int connection = 0;
/* Don't start ESD if it's not running */
if (SDL_getenv("ESD_NO_SPAWN") == NULL) {
SDL_putenv("ESD_NO_SPAWN=1");
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection < 0) {
UnloadESDLibrary();
SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
return 0;
}
SDL_NAME(esd_close) (connection);
}
/* Set the function pointers */
impl->OpenDevice = ESD_OpenDevice;
impl->PlayDevice = ESD_PlayDevice;
impl->WaitDevice = ESD_WaitDevice;
impl->GetDeviceBuf = ESD_GetDeviceBuf;
impl->CloseDevice = ESD_CloseDevice;
impl->Deinitialize = ESD_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
AudioBootStrap ESD_bootstrap = {
ESD_DRIVER_NAME, "Enlightened Sound Daemon", ESD_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -47,13 +47,5 @@ struct SDL_PrivateAudioData
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_esdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,6 +21,7 @@
*/
#include "SDL_config.h"
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
#include "SDL_audio.h"
......@@ -28,79 +29,233 @@
#include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h"
#define DEBUG_COREAUDIO 0
/* Audio driver functions */
static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Core_WaitAudio(_THIS);
static void Core_PlayAudio(_THIS);
static Uint8 *Core_GetAudioBuf(_THIS);
static void Core_CloseAudio(_THIS);
typedef struct COREAUDIO_DeviceList
{
AudioDeviceID id;
const char *name;
} COREAUDIO_DeviceList;
/* Audio driver bootstrap functions */
static COREAUDIO_DeviceList *inputDevices = NULL;
static int inputDeviceCount = 0;
static COREAUDIO_DeviceList *outputDevices = NULL;
static int outputDeviceCount = 0;
static int
Audio_Available(void)
static void
free_device_list(COREAUDIO_DeviceList **devices, int *devCount)
{
return (1);
if (*devices) {
int i = *devCount;
while (i--)
SDL_free((void *) (*devices)[i].name);
SDL_free(*devices);
*devices = NULL;
}
*devCount = 0;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
build_device_list(int iscapture, COREAUDIO_DeviceList **devices, int *devCount)
{
SDL_free(device->hidden);
SDL_free(device);
Boolean outWritable = 0;
OSStatus result = noErr;
UInt32 size = 0;
AudioDeviceID *devs = NULL;
UInt32 i = 0;
UInt32 max = 0;
free_device_list(devices, devCount);
result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
&size, &outWritable);
if (result != kAudioHardwareNoError)
return;
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
return;
max = size / sizeof (AudioDeviceID);
*devices = (COREAUDIO_DeviceList *) SDL_malloc(max * sizeof (**devices));
if (*devices == NULL)
return;
result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
&size, devs);
if (result != kAudioHardwareNoError)
return;
for (i = 0; i < max; i++) {
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
result = AudioDeviceGetPropertyInfo(dev, 0, iscapture,
kAudioDevicePropertyStreamConfiguration,
&size, &outWritable);
if (result != noErr)
continue;
buflist = (AudioBufferList *) SDL_malloc(size);
if (buflist == NULL)
continue;
result = AudioDeviceGetProperty(dev, 0, iscapture,
kAudioDevicePropertyStreamConfiguration,
&size, buflist);
if (result == noErr) {
UInt32 j;
for (j = 0; j < buflist->mNumberBuffers; j++) {
if (buflist->mBuffers[j].mNumberChannels > 0) {
usable = 1;
break;
}
}
}
SDL_free(buflist);
if (!usable)
continue;
size = sizeof (CFStringRef);
result = AudioDeviceGetProperty(dev, 0, iscapture,
kAudioObjectPropertyName,
&size, &cfstr);
if (result != kAudioHardwareNoError)
continue;
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) SDL_malloc(len + 1);
usable = ( (ptr != NULL) &&
(CFStringGetCString(cfstr,ptr,len+1,kCFStringEncodingUTF8)) );
CFRelease(cfstr);
if (usable) {
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len-1] == ' ')) {
len--;
}
usable = (len > 0);
}
if (!usable) {
SDL_free(ptr);
} else {
ptr[len] = '\0';
#if DEBUG_COREAUDIO
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
((iscapture) ? "capture" : "output"),
(int) *devCount, ptr, (int) dev);
#endif
(*devices)[*devCount].id = dev;
(*devices)[*devCount].name = ptr;
(*devCount)++;
}
}
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static inline void
build_device_lists(void)
{
SDL_AudioDevice *this;
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
static inline void
free_device_lists(void)
{
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
}
static int
find_device_id(const char *devname, int iscapture, AudioDeviceID *id)
{
int i = ((iscapture) ? inputDeviceCount : outputDeviceCount);
COREAUDIO_DeviceList *devs = ((iscapture) ? inputDevices : outputDevices);
while (i--) {
if (SDL_strcmp(devname, devs->name) == 0) {
*id = devs->id;
return 1;
}
return (0);
devs++;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Core_OpenAudio;
this->WaitAudio = Core_WaitAudio;
this->PlayAudio = Core_PlayAudio;
this->GetAudioBuf = Core_GetAudioBuf;
this->CloseAudio = Core_CloseAudio;
return 0;
}
static int
COREAUDIO_DetectDevices(int iscapture)
{
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
}
this->free = Audio_DeleteDevice;
return 0; /* shouldn't ever hit this. */
}
return this;
static const char *
COREAUDIO_GetDeviceName(int index, int iscapture)
{
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index].name;
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index].name;
}
SDL_SetError("No such device");
return NULL;
}
static void
COREAUDIO_Deinitialize(void)
{
free_device_lists();
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "Mac OS X CoreAudio",
Audio_Available, Audio_CreateDevice
};
/* The CoreAudio callback */
static OSStatus
audioCallback(void *inRefCon,
AudioUnitRenderActionFlags inActionFlags,
outputCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, AudioBuffer * ioData)
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioDataList)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
AudioBuffer *ioData = &ioDataList->mBuffers[0];
UInt32 remaining, len;
void *ptr;
/* Is there ever more than one buffer, and what do you do with it? */
if (ioDataList->mNumberBuffers != 1) {
return noErr;
}
/* Only do anything if audio is enabled and not paused */
if (!this->enabled || this->paused) {
SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
......@@ -118,109 +273,251 @@ audioCallback(void *inRefCon,
remaining = ioData->mDataByteSize;
ptr = ioData->mData;
while (remaining > 0) {
if (bufferOffset >= bufferSize) {
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */
SDL_memset(buffer, this->spec.silence, bufferSize);
SDL_memset(this->hidden->buffer, this->spec.silence,
this->hidden->bufferSize);
SDL_mutexP(this->mixer_lock);
(*this->spec.callback) (this->spec.userdata, buffer, bufferSize);
(*this->spec.callback) (this->spec.userdata, this->hidden->buffer,
this->hidden->bufferSize);
SDL_mutexV(this->mixer_lock);
bufferOffset = 0;
this->hidden->bufferOffset = 0;
}
len = bufferSize - bufferOffset;
len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining)
len = remaining;
SDL_memcpy(ptr, (char *) buffer + bufferOffset, len);
SDL_memcpy(ptr,
(char *) this->hidden->buffer + this->hidden->bufferOffset,
len);
ptr = (char *) ptr + len;
remaining -= len;
bufferOffset += len;
this->hidden->bufferOffset += len;
}
return 0;
}
/* Dummy functions -- we don't use thread-based audio */
void
Core_WaitAudio(_THIS)
static OSStatus
inputCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData)
{
return;
//err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer);
// !!! FIXME: write me!
return noErr;
}
void
Core_PlayAudio(_THIS)
{
return;
}
Uint8 *
Core_GetAudioBuf(_THIS)
static void
COREAUDIO_CloseDevice(_THIS)
{
return (NULL);
if (this->hidden != NULL) {
OSStatus result = noErr;
AURenderCallbackStruct callback;
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
const int iscapture = this->iscapture;
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
kAudioUnitScope_Input);
/* stop processing the audio unit */
result = AudioOutputUnitStop(this->hidden->audioUnit);
/* Remove the input callback */
SDL_memset(&callback, '\0', sizeof (AURenderCallbackStruct));
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_SetRenderCallback,
scope, bus, &callback, sizeof (callback));
CloseComponent(this->hidden->audioUnit);
SDL_free(this->hidden->buffer);
SDL_free(this->hidden);
this->hidden = NULL;
}
}
void
Core_CloseAudio(_THIS)
{
OSStatus result;
struct AudioUnitInputCallback callback;
/* stop processing the audio unit */
result = AudioOutputUnitStop(outputAudioUnit);
if (result != noErr) {
SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
return;
#define CHECK_RESULT(msg) \
if (result != noErr) { \
COREAUDIO_CloseDevice(this); \
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
return 0; \
}
/* Remove the input callback */
callback.inputProc = 0;
callback.inputProcRefCon = 0;
result = AudioUnitSetProperty(outputAudioUnit,
kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Input,
0, &callback, sizeof(callback));
if (result != noErr) {
SDL_SetError
("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
return;
static int
find_device_by_name(_THIS, const char *devname, int iscapture)
{
AudioDeviceID devid = 0;
OSStatus result = noErr;
UInt32 size = 0;
UInt32 alive = 0;
pid_t pid = 0;
if (devname == NULL) {
size = sizeof (AudioDeviceID);
const AudioHardwarePropertyID propid =
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
kAudioHardwarePropertyDefaultOutputDevice);
result = AudioHardwareGetProperty(propid, &size, &devid);
CHECK_RESULT("AudioHardwareGetProperty (default device)");
} else {
if (!find_device_id(devname, iscapture, &devid)) {
SDL_SetError("CoreAudio: No such audio device.");
return 0;
}
}
result = CloseComponent(outputAudioUnit);
if (result != noErr) {
SDL_SetError("Core_CloseAudio: CloseComponent");
return;
size = sizeof (alive);
result = AudioDeviceGetProperty(devid, 0, iscapture,
kAudioDevicePropertyDeviceIsAlive,
&size, &alive);
CHECK_RESULT("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
if (!alive) {
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
return 0;
}
SDL_free(buffer);
}
size = sizeof (pid);
result = AudioDeviceGetProperty(devid, 0, iscapture,
kAudioDevicePropertyHogMode, &size, &pid);
#define CHECK_RESULT(msg) \
if (result != noErr) { \
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
return -1; \
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio: requested device is being hogged.");
return 0;
}
this->hidden->deviceID = devid;
return 1;
}
int
Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
static int
prepare_audiounit(_THIS, const char *devname, int iscapture,
const AudioStreamBasicDescription *strdesc)
{
OSStatus result = noErr;
Component comp;
AURenderCallbackStruct callback;
ComponentDescription desc;
struct AudioUnitInputCallback callback;
Component comp = NULL;
int use_system_device = 0;
UInt32 enableIO = 0;
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
kAudioUnitScope_Input);
if (!find_device_by_name(this, devname, iscapture)) {
SDL_SetError("Couldn't find requested CoreAudio device");
return 0;
}
SDL_memset(&desc, '\0', sizeof(ComponentDescription));
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
comp = FindNextComponent(NULL, &desc);
if (comp == NULL) {
SDL_SetError("Couldn't find requested CoreAudio component");
return 0;
}
/* Open & initialize the audio unit */
result = OpenAComponent(comp, &this->hidden->audioUnit);
CHECK_RESULT("OpenAComponent");
// !!! FIXME: this is wrong?
enableIO = ((iscapture) ? 1 : 0);
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input, input_bus,
&enableIO, sizeof (enableIO));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO input)");
// !!! FIXME: this is wrong?
enableIO = ((iscapture) ? 0 : 1);
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output, output_bus,
&enableIO, sizeof (enableIO));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO output)");
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global, 0,
&this->hidden->deviceID,
sizeof (AudioDeviceID));
CHECK_RESULT("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
/* Set the data format of the audio unit. */
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_StreamFormat,
scope, bus, strdesc, sizeof (*strdesc));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
/* Set the audio callback */
SDL_memset(&callback, '\0', sizeof (AURenderCallbackStruct));
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_SetRenderCallback,
scope, bus, &callback, sizeof (callback));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate a sample buffer */
this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
result = AudioUnitInitialize(this->hidden->audioUnit);
CHECK_RESULT("AudioUnitInitialize");
/* Finally, start processing of the audio unit */
result = AudioOutputUnitStart(this->hidden->audioUnit);
CHECK_RESULT("AudioOutputUnitStart");
/* We're running! */
return 1;
}
static int
COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
{
AudioStreamBasicDescription strdesc;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Setup a AudioStreamBasicDescription with the requested format */
memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = spec->channels;
strdesc.mSampleRate = spec->freq;
strdesc.mChannelsPerFrame = this->spec.channels;
strdesc.mSampleRate = this->spec.freq;
strdesc.mFramesPerPacket = 1;
while ((!valid_datatype) && (test_format)) {
spec->format = test_format;
this->spec.format = test_format;
/* Just a list of valid SDL formats, so people don't pass junk here. */
switch (test_format) {
case AUDIO_U8:
......@@ -234,13 +531,13 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
case AUDIO_F32LSB:
case AUDIO_F32MSB:
valid_datatype = 1;
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format);
if (SDL_AUDIO_ISBIGENDIAN(spec->format))
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
if (SDL_AUDIO_ISFLOAT(spec->format))
if (SDL_AUDIO_ISFLOAT(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
else if (SDL_AUDIO_ISSIGNED(spec->format))
else if (SDL_AUDIO_ISSIGNED(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
break;
}
......@@ -248,7 +545,7 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format");
return (-1);
return 0;
}
strdesc.mBytesPerFrame =
......@@ -256,52 +553,31 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
strdesc.mBytesPerPacket =
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
/* Locate the default output audio unit */
memset(&desc, '\0', sizeof(ComponentDescription));
desc.componentType = kAudioUnitComponentType;
desc.componentSubType = kAudioUnitSubType_Output;
desc.componentManufacturer = kAudioUnitID_DefaultOutput;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = FindNextComponent(NULL, &desc);
if (comp == NULL) {
SDL_SetError
("Failed to start CoreAudio: FindNextComponent returned NULL");
return -1;
if (!prepare_audiounit(this, devname, iscapture, &strdesc)) {
return 0; /* prepare_audiounit() will call SDL_SetError()... */
}
/* Open & initialize the default output audio unit */
result = OpenAComponent(comp, &outputAudioUnit);
CHECK_RESULT("OpenAComponent")
result = AudioUnitInitialize(outputAudioUnit);
CHECK_RESULT("AudioUnitInitialize")
/* Set the input format of the audio unit. */
result = AudioUnitSetProperty(outputAudioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0, &strdesc, sizeof(strdesc));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
/* Set the audio callback */
callback.inputProc = audioCallback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(outputAudioUnit,
kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Input,
0, &callback, sizeof(callback));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
return 1; /* good to go. */
}
/* Allocate a sample buffer */
bufferOffset = bufferSize = this->spec.size;
buffer = SDL_malloc(bufferSize);
static int
COREAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = COREAUDIO_DetectDevices;
impl->GetDeviceName = COREAUDIO_GetDeviceName;
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
impl->ProvidesOwnCallbackThread = 1;
/* Finally, start processing of the audio unit */
result = AudioOutputUnitStart(outputAudioUnit);
CHECK_RESULT("AudioOutputUnitStart")
/* We're running! */
return (1);
build_device_lists(); /* do an initial check for devices... */
return 1;
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "Mac OS X CoreAudio", COREAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,22 +26,17 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
AudioUnit outputAudioUnit;
AudioUnit audioUnit;
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
AudioDeviceID deviceID;
};
/* Old variable names */
#define outputAudioUnit (this->hidden->outputAudioUnit)
#define buffer (this->hidden->buffer)
#define bufferOffset (this->hidden->bufferOffset)
#define bufferSize (this->hidden->bufferSize)
#endif /* _SDL_coreaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,11 +21,16 @@
*/
#include "SDL_config.h"
/* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
#if defined(__APPLE__) && defined(__MACH__)
# define SDL_MACOS_NAME "Mac OS X"
# include <Carbon/Carbon.h>
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
# define SDL_MACOS_NAME "Mac OS 9"
# include <Carbon.h>
#else
# define SDL_MACOS_NAME "Mac OS 9"
# include <Sound.h> /* SoundManager interface */
# include <Gestalt.h>
# include <DriverServices.h>
......@@ -45,72 +50,6 @@
#include "../SDL_sysaudio.h"
#include "SDL_romaudio.h"
/* Audio driver functions */
static void Mac_CloseAudio(_THIS);
static int Mac_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mac_LockAudio(_THIS);
static void Mac_UnlockAudio(_THIS);
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mac_OpenAudio;
this->CloseAudio = Mac_CloseAudio;
this->LockAudio = Mac_LockAudio;
this->UnlockAudio = Mac_UnlockAudio;
this->free = Audio_DeleteDevice;
#ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
this->LockAudio = NULL;
this->UnlockAudio = NULL;
#endif
return this;
}
AudioBootStrap SNDMGR_bootstrap = {
"sndmgr", "MacOS SoundManager 3.0",
Audio_Available, Audio_CreateDevice
};
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
/* This works correctly on Mac OS X */
#pragma options align=power
static volatile SInt32 audio_is_locked = 0;
......@@ -121,6 +60,7 @@ static volatile UInt32 running = 0;
static CmpSoundHeader header;
static volatile Uint32 fill_me = 0;
static void
mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
{
......@@ -150,13 +90,13 @@ mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
}
static void
Mac_LockAudio(_THIS)
SNDMGR_LockDevice(_THIS)
{
IncrementAtomic((SInt32 *) & audio_is_locked);
}
static void
Mac_UnlockAudio(_THIS)
SNDMGR_UnlockDevice(_THIS)
{
SInt32 oldval;
......@@ -198,7 +138,7 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
cmd.param2 = (long) &header;
SndDoCommand(chan, &cmd, 0);
memset(buffer[fill_me], 0, audio->spec.size);
SDL_memset(buffer[fill_me], 0, audio->spec.size);
/*
* if audio device isn't locked, mix the next buffer to be queued in
......@@ -219,14 +159,25 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
}
static int
Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
SNDMGR_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_AudioSpec *spec = &this->spec;
SndChannelPtr channel = NULL;
SndCallBackUPP callback;
int sample_bits;
int i;
long initOptions;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* !!! FIXME: iterate through format matrix... */
/* Very few conversions are required, but... */
switch (spec->format) {
case AUDIO_S8:
......@@ -242,10 +193,10 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
spec->format = AUDIO_F32MSB;
break;
}
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* initialize bufferCmd header */
memset(&header, 0, sizeof(header));
SDL_memset(&header, 0, sizeof(header));
callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
sample_bits = spec->size / spec->samples / spec->channels * 8;
......@@ -278,20 +229,23 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* allocate 2 buffers */
for (i = 0; i < 2; i++) {
buffer[i] = (UInt8 *) malloc(sizeof(UInt8) * spec->size);
buffer[i] = (UInt8 *) SDL_malloc(sizeof(UInt8) * spec->size);
if (buffer[i] == NULL) {
SNDMGR_CloseDevice(this);
SDL_OutOfMemory();
return (-1);
return 0;
}
memset(buffer[i], 0, spec->size);
SDL_memset(buffer[i], 0, spec->size);
}
/* Create the sound manager channel */
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
if (channel == NULL) {
SNDMGR_CloseDevice(this);
SDL_OutOfMemory();
return (-1);
return 0;
}
this->hidden->channel = channel;
if (spec->channels >= 2) {
initOptions = initStereo;
} else {
......@@ -300,10 +254,9 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
channel->userInfo = (long) this;
channel->qLength = 128;
if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
SNDMGR_CloseDevice(this);
SDL_SetError("Unable to create audio channel");
SDL_free(channel);
channel = NULL;
return (-1);
return 0;
}
/* start playback */
......@@ -319,16 +272,15 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
}
static void
Mac_CloseAudio(_THIS)
SNDMGR_CloseDevice(_THIS)
{
int i;
running = 0;
if (channel) {
SndDisposeChannel(channel, true);
channel = NULL;
if (this->hidden->channel) {
SndDisposeChannel(this->hidden->channel, true);
this->hidden->channel = NULL;
}
for (i = 0; i < 2; ++i) {
......@@ -337,193 +289,31 @@ Mac_CloseAudio(_THIS)
buffer[i] = NULL;
}
}
}
#else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
static void
Mac_LockAudio(_THIS)
{
/* no-op. */
}
static void
Mac_UnlockAudio(_THIS)
{
/* no-op. */
}
/* This function is called by Sound Manager when it has exhausted one of
the buffers, so we'll zero it to silence and fill it with audio if
we're not paused.
*/
static pascal void
sndDoubleBackProc(SndChannelPtr chan, SndDoubleBufferPtr newbuf)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) newbuf->dbUserInfo[0];
/* If audio is quitting, don't do anything */
if (!audio->enabled) {
return;
}
memset(newbuf->dbSoundData, 0, audio->spec.size);
newbuf->dbNumFrames = audio->spec.samples;
if (!audio->paused) {
if (audio->convert.needed) {
audio->spec.callback(audio->spec.userdata,
(Uint8 *) audio->convert.buf,
audio->convert.len);
SDL_ConvertAudio(&audio->convert);
#if 0
if (audio->convert.len_cvt != audio->spec.size) {
/* Uh oh... probably crashes here */ ;
}
#endif
SDL_memcpy(newbuf->dbSoundData, audio->convert.buf,
audio->convert.len_cvt);
} else {
audio->spec.callback(audio->spec.userdata,
(Uint8 *) newbuf->dbSoundData,
audio->spec.size);
}
}
newbuf->dbFlags |= dbBufferReady;
SDL_free(this->hidden);
this->hidden = NULL;
}
static int
DoubleBufferAudio_Available(void)
SNDMGR_Init(SDL_AudioDriverImpl *impl)
{
int available;
NumVersion sndversion;
long response;
available = 0;
sndversion = SndSoundManagerVersion();
if (sndversion.majorRev >= 3) {
if (Gestalt(gestaltSoundAttr, &response) == noErr) {
if ((response & (1 << gestaltSndPlayDoubleBuffer))) {
available = 1;
}
}
} else {
if (Gestalt(gestaltSoundAttr, &response) == noErr) {
if ((response & (1 << gestaltHasASC))) {
available = 1;
}
}
}
return (available);
}
static void
Mac_CloseAudio(_THIS)
{
int i;
if (channel != NULL) {
/* Clean up the audio channel */
SndDisposeChannel(channel, true);
channel = NULL;
}
for (i = 0; i < 2; ++i) {
if (audio_buf[i]) {
SDL_free(audio_buf[i]);
audio_buf[i] = NULL;
}
}
}
static int
Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
SndDoubleBufferHeader2 audio_dbh;
int i;
long initOptions;
int sample_bits;
SndDoubleBackUPP doubleBackProc;
/* Check to make sure double-buffered audio is available */
if (!DoubleBufferAudio_Available()) {
SDL_SetError("Sound manager doesn't support double-buffering");
return (-1);
}
/* Very few conversions are required, but... */
switch (spec->format) {
case AUDIO_S8:
spec->format = AUDIO_U8;
break;
case AUDIO_U16LSB:
spec->format = AUDIO_S16LSB;
break;
case AUDIO_U16MSB:
spec->format = AUDIO_S16MSB;
break;
}
SDL_CalculateAudioSpec(spec);
/* initialize the double-back header */
SDL_memset(&audio_dbh, 0, sizeof(audio_dbh));
doubleBackProc = NewSndDoubleBackProc(sndDoubleBackProc);
sample_bits = spec->size / spec->samples / spec->channels * 8;
audio_dbh.dbhNumChannels = spec->channels;
audio_dbh.dbhSampleSize = sample_bits;
audio_dbh.dbhCompressionID = 0;
audio_dbh.dbhPacketSize = 0;
audio_dbh.dbhSampleRate = spec->freq << 16;
audio_dbh.dbhDoubleBack = doubleBackProc;
audio_dbh.dbhFormat = 0;
/* Note that we install the 16bitLittleEndian Converter if needed. */
if (spec->format == 0x8010) {
audio_dbh.dbhCompressionID = fixedCompression;
audio_dbh.dbhFormat = k16BitLittleEndianFormat;
}
/* allocate the 2 double-back buffers */
for (i = 0; i < 2; ++i) {
audio_buf[i] = SDL_calloc(1, sizeof(SndDoubleBuffer) + spec->size);
if (audio_buf[i] == NULL) {
SDL_OutOfMemory();
return (-1);
}
audio_buf[i]->dbNumFrames = spec->samples;
audio_buf[i]->dbFlags = dbBufferReady;
audio_buf[i]->dbUserInfo[0] = (long) this;
audio_dbh.dbhBufferPtr[i] = audio_buf[i];
}
/* Create the sound manager channel */
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
if (channel == NULL) {
SDL_OutOfMemory();
return (-1);
}
if (spec->channels >= 2) {
initOptions = initStereo;
} else {
initOptions = initMono;
}
channel->userInfo = 0;
channel->qLength = 128;
if (SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr) {
SDL_SetError("Unable to create audio channel");
SDL_free(channel);
channel = NULL;
return (-1);
}
/* Start playback */
if (SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr) & audio_dbh)
!= noErr) {
SDL_SetError("Unable to play double buffered audio");
return (-1);
}
/* Set the function pointers */
impl->OpenDevice = SNDMGR_OpenDevice;
impl->CloseDevice = SNDMGR_CloseDevice;
impl->ProvidesOwnCallbackThread = 1;
impl->OnlyHasDefaultOutputDevice = 1;
/* Mac OS X uses threaded audio, so normal thread code is okay */
#ifndef __MACOSX__
impl->LockDevice = SNDMGR_LockDevice;
impl->UnlockDevice = SNDMGR_UnlockDevice;
impl->SkipMixerLock = 1;
#endif
return 1;
}
#endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
AudioBootStrap SNDMGR_bootstrap = {
"sndmgr", SDL_MACOS_NAME " SoundManager", SNDMGR_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,27 +26,14 @@
#include "../SDL_sysaudio.h"
/* This is Ryan's improved MacOS sound code, with locking support */
#define USE_RYANS_SOUNDCODE
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* Sound manager audio channel */
SndChannelPtr channel;
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
/* FIXME: Add Ryan's static data here */
#else
/* Double buffering variables */
SndDoubleBufferPtr audio_buf[2];
#endif
};
/* Old variable names */
#define channel (this->hidden->channel)
#define audio_buf (this->hidden->audio_buf)
#endif /* _SDL_romaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -61,105 +61,8 @@
static unsigned long cookie_snd, cookie_mch;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
/*--- Audio driver bootstrap functions ---*/
static int
Audio_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return 0;
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 8 bits audio */
if ((cookie_snd & SND_8BIT) == 0) {
DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
return (0);
}
/* Check if audio is lockable */
if (cookie_snd & SND_16BIT) {
if (Locksnd() != 1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return (0);
}
Unlocksnd();
}
DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
Audio_Available, Audio_CreateDevice
};
static void
Mint_LockAudio(_THIS)
MINTDMA8_LockDevice(_THIS)
{
void *oldpile;
......@@ -170,7 +73,7 @@ Mint_LockAudio(_THIS)
}
static void
Mint_UnlockAudio(_THIS)
MINTDMA8_UnlockDevice(_THIS)
{
void *oldpile;
......@@ -181,57 +84,59 @@ Mint_UnlockAudio(_THIS)
}
static void
Mint_CloseAudio(_THIS)
MINTDMA8_CloseDevice(_THIS)
{
void *oldpile;
if (this->hidden != NULL) {
/* Stop replay */
void *oldpile = (void *) Super(0);
/* Stop replay */
oldpile = (void *) Super(0);
DMAAUDIO_IO.control = 0;
Super(oldpile);
DMAAUDIO_IO.control = 0;
Super(oldpile);
DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
/* Disable interrupt */
Jdisint(MFP_DMASOUND);
/* Disable interrupt */
Jdisint(MFP_DMASOUND);
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {}
DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
SDL_free(this->buffer);
this->buffer = NULL;
}
}
static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
MINTDMA8_CheckAudio(_THIS)
{
int i, masterprediv, sfreq;
unsigned long masterclock;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (this->spec.channels > 2) {
this->spec.channels = 2; /* no more than stereo! */
}
/* Check formats available */
spec->format = AUDIO_S8;
this->spec.format = AUDIO_S8;
/* Calculate and select the closest frequency */
sfreq = 0;
......@@ -272,22 +177,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
}
#endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0;
}
static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
MINTDMA8_InitAudio(_THIS)
{
void *oldpile;
unsigned long buffer;
......@@ -316,7 +221,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
DMAAUDIO_IO.end_low = buffer & 255;
mode = 3 - MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if (spec->channels == 1) {
if (this->spec.channels == 1) {
mode |= 1 << 7;
}
DMAAUDIO_IO.sound_ctrl = mode;
......@@ -339,29 +244,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
}
static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
MINTDMA8_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) {
return -1;
if (MINTDMA8_CheckAudio(this) == -1) {
return 0;
}
SDL_CalculateAudioSpec(spec);
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_CalculateAudioSpec(&this->spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
SDL_free(this->hidden);
this->hidden = NULL;
SDL_OutOfMemory();
return 0;
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
SDL_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
SDL_MintAudio_audiosize = spec->size;
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
......@@ -372,9 +288,56 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
MINTDMA8_InitAudio(this);
return (1); /* We don't use threaded audio */
return 1; /* good to go. */
}
static int
MINTDMA8_Init(SDL_AudioDriverImpl *impl)
{
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 8 bits audio */
if ((cookie_snd & SND_8BIT) == 0) {
SDL_SetError(DEBUG_NAME "no 8 bits sound");
return 0;
}
/* Check if audio is lockable */
if (cookie_snd & SND_16BIT) {
if (Locksnd() != 1) {
SDL_SetError(DEBUG_NAME "audio locked by other application");
return 0;
}
Unlocksnd();
}
DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
/* Set the function pointers */
impl->OpenDevice = MINTDMA8_OpenDevice;
impl->CloseDevice = MINTDMA8_CloseDevice;
impl->LockAudio = MINTDMA8_LockAudio;
impl->UnlockAudio = MINTDMA8_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->SkipMixerLock = 1;
return 1;
}
AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver", MINTDMA8_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -63,176 +63,83 @@ static unsigned long cookie_snd, cookie_gsxb;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
/* GSXB callbacks */
static void Mint_GsxbInterrupt(void);
static void Mint_GsxbNullInterrupt(void);
/*--- Audio driver bootstrap functions ---*/
static int
Audio_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return (0);
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return (0);
}
/* Cookie GSXB present ? */
cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
/* Is it GSXB ? */
if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n"));
return (0);
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return (0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
return (1);
}
static void MINTGSXB_GsxbInterrupt(void);
static void MINTGSXB_GsxbNullInterrupt(void);
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
Audio_Available, Audio_CreateDevice
};
static void
Mint_LockAudio(_THIS)
MINTGSXB_LockDevice(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void
Mint_UnlockAudio(_THIS)
MINTGSXB_UnlockDevice(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
}
static void
Mint_CloseAudio(_THIS)
MINTGSXB_CloseDevice(_THIS)
{
/* Stop replay */
Buffoper(0);
if (this->hidden != NULL) {
/* Stop replay */
Buffoper(0);
/* Uninstall interrupt */
if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt) < 0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
}
/* Uninstall interrupt */
if (NSetinterrupt(2, SI_NONE, MINTGSXB_GsxbNullInterrupt) < 0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
/* Unlock sound system */
Unlocksnd();
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
MINTGSXB_CheckAudio(_THIS)
{
long snd_format;
int i, resolution, format_signed, format_bigendian;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
resolution = SDL_AUDIO_BITSIZE(spec->format);
format_signed = SDL_AUDIO_ISSIGNED(spec->format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format);
resolution = SDL_AUDIO_BITSIZE(this->spec.format);
format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", resolution));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", format_signed));
DEBUG_PRINT(("big endian=%d, ", format_bigendian));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
if (this->spec.channels > 2) {
this->spec.channels = 2; /* no more than stereo! */
}
while ((!valid_datatype) && (test_format)) {
/* Check formats available */
snd_format = Sndstatus(SND_QUERYFORMATS);
spec->format = test_format;
resolution = SDL_AUDIO_BITSIZE(spec->format);
format_signed = SDL_AUDIO_ISSIGNED(spec->format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format);
this->spec.format = test_format;
resolution = SDL_AUDIO_BITSIZE(this->spec.format);
format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
switch (test_format) {
case AUDIO_U8:
case AUDIO_S8:
......@@ -279,14 +186,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
/* Ok */
} else if (snd_format & SND_FORMATUNSIGNED) {
/* Give unsigned format */
spec->format = spec->format & (~SDL_AUDIO_MASK_SIGNED);
this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_SIGNED);
}
} else {
if (snd_format & SND_FORMATUNSIGNED) {
/* Ok */
} else if (snd_format & SND_FORMATSIGNED) {
/* Give signed format */
spec->format |= SDL_AUDIO_MASK_SIGNED;
this->spec.format |= SDL_AUDIO_MASK_SIGNED;
}
}
......@@ -295,14 +202,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
/* Ok */
} else if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Give little endian format */
spec->format = spec->format & (~SDL_AUDIO_MASK_ENDIAN);
this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_ENDIAN);
}
} else {
if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Ok */
} else if (snd_format & SND_FORMATBIGENDIAN) {
/* Give big endian format */
spec->format |= SDL_AUDIO_MASK_ENDIAN;
this->spec.format |= SDL_AUDIO_MASK_ENDIAN;
}
}
......@@ -324,22 +231,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
}
#endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0;
}
static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
MINTGSXB_InitAudio(_THIS)
{
int channels_mode, prediv;
void *buffer;
......@@ -352,23 +259,23 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
Setmontracks(0);
/* Select replay format */
switch (SDL_AUDIO_BITSIZE(spec->format)) {
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8:
if (spec->channels == 2) {
if (this->spec.channels == 2) {
channels_mode = STEREO8;
} else {
channels_mode = MONO8;
}
break;
case 16:
if (spec->channels == 2) {
if (this->spec.channels == 2) {
channels_mode = STEREO16;
} else {
channels_mode = MONO16;
}
break;
case 32:
if (spec->channels == 2) {
if (this->spec.channels == 2) {
channels_mode = STEREO32;
} else {
channels_mode = MONO32;
......@@ -387,12 +294,12 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
/* Install interrupt */
if (NSetinterrupt(2, SI_PLAY, Mint_GsxbInterrupt) < 0) {
if (NSetinterrupt(2, SI_PLAY, MINTGSXB_GsxbInterrupt) < 0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
}
......@@ -402,35 +309,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
}
static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
MINTGSXB_OpenDevice(_THIS, const char *devname, int iscapture)
{
/* Lock sound system */
if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return (-1);
SDL_SetError("MINTGSXB_OpenDevice: Audio system already in use");
return 0;
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) {
return -1;
if (MINTGSXB_CheckAudio(this) == -1) {
return 0;
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
SDL_free(this->hidden);
this->hidden = NULL;
SDL_OutOfMemory();
return 0;
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
SDL_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
SDL_MintAudio_audiosize = spec->size;
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
......@@ -441,13 +359,13 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
MINTGSXB_InitAudio(this);
return (1); /* We don't use threaded audio */
return 1; /* good to go. */
}
static void
Mint_GsxbInterrupt(void)
MINTGSXB_GsxbInterrupt(void)
{
Uint8 *newbuf;
......@@ -465,8 +383,57 @@ Mint_GsxbInterrupt(void)
}
static void
Mint_GsxbNullInterrupt(void)
MINTGSXB_GsxbNullInterrupt(void)
{
}
static int
MINTGSXB_Init(SDL_AudioDriverImpl *impl)
{
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
SDL_SetError(DEBUG_NAME "no 16-bit sound");
return 0;
}
/* Cookie GSXB present ? */
cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
/* Is it GSXB ? */
if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
SDL_SetError(DEBUG_NAME "no GSXB audio");
return 0;
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
SDL_SetError(DEBUG_NAME "audio locked by other application");
return 0;
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
/* Set the function pointers */
impl->OpenDevice = MINTGSXB_OpenDevice;
impl->CloseDevice = MINTGSXB_CloseDevice;
impl->LockAudio = MINTGSXB_LockAudio;
impl->UnlockAudio = MINTGSXB_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->SkipMixerLock = 1;
return 1;
}
AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver", MINTGSXB_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -61,192 +61,82 @@
/*--- Static variables ---*/
static unsigned long cookie_snd, cookie_mch;
static cookie_mcsn_t *cookie_mcsn;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
/*--- Audio driver bootstrap functions ---*/
static int
Audio_Available(void)
{
unsigned long dummy;
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return (0);
}
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return (0);
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return (0);
}
/* Cookie MCSN present ? */
if (Getcookie(C_McSn, (long *) &cookie_mcsn) != C_FOUND) {
DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n"));
return (0);
}
/* Check if interrupt at end of replay */
if (cookie_mcsn->pint == 0) {
DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n"));
return (0);
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return (0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver",
Audio_Available, Audio_CreateDevice
};
static unsigned long cookie_snd = 0;
static unsigned long cookie_mch = 0;
static cookie_mcsn_t *cookie_mcsn = NULL;
static void
Mint_LockAudio(_THIS)
MINTMCSN_LockDevice(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void
Mint_UnlockAudio(_THIS)
MINTMCSN_UnlockDevice(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
}
static void
Mint_CloseAudio(_THIS)
MINTMCSN_CloseDevice(_THIS)
{
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (this->hidden != NULL) {
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
/* Unlock sound system */
Unlocksnd();
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
MINTMCSN_CheckAudio(_THIS)
{
int i;
unsigned long masterclock, masterprediv;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (this->spec.channels > 2) {
this->spec.channels = 2; /* no more than stereo! */
}
/* Check formats available */
MINTAUDIO_freqcount = 0;
switch (cookie_mcsn->play) {
case MCSN_ST:
spec->channels = 1;
spec->format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */
this->spec.channels = 1;
this->spec.format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */
SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1);
break;
case MCSN_TT: /* Also STE, Mega STE */
spec->format = AUDIO_S8;
this->spec.format = AUDIO_S8;
masterclock = MASTERCLOCK_STE;
masterprediv = MASTERPREDIV_STE;
if ((cookie_mch >> 16) == MCH_TT) {
......@@ -280,10 +170,10 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
(1 << i) - 1, -1);
}
}
spec->format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
if ((SDL_AUDIO_BITSIZE(spec->format)) == 16) {
spec->format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */
spec->channels = 2; /* 16 bits always stereo */
this->spec.format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
if ((SDL_AUDIO_BITSIZE(this->spec.format)) == 16) {
this->spec.format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */
this->spec.channels = 2; /* 16 bits always stereo */
}
break;
}
......@@ -297,22 +187,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
}
#endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0;
}
static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
MINTMCSN_InitAudio(_THIS)
{
int channels_mode, prediv, dmaclock;
void *buffer;
......@@ -329,9 +219,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */
channels_mode = STEREO16;
switch (SDL_AUDIO_BITSIZE(spec->format)) {
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8:
if (spec->channels == 2) {
if (this->spec.channels == 2) {
channels_mode = STEREO8;
} else {
channels_mode = MONO8;
......@@ -358,7 +248,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
......@@ -381,35 +271,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
}
static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
MINTMCSN_OpenDevice(_THIS, const char *devname, int iscapture)
{
/* Lock sound system */
if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return (-1);
SDL_SetError("MINTMCSN_OpenDevice: Audio system already in use");
return 0;
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) {
return -1;
if (MINTMCSN_CheckAudio(this) == -1) {
return 0;
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
SDL_free(this->hidden);
this->hidden = NULL;
SDL_OutOfMemory();
return 0;
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
SDL_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
SDL_MintAudio_audiosize = spec->size;
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
......@@ -420,9 +321,75 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
MINTMCSN_InitAudio(this);
return 1; /* good to go. */
}
static int
MINTMCSN_Init(SDL_AudioDriverImpl *impl)
{
unsigned long dummy = 0;
SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return 0;
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
SDL_SetError(DEBUG_NAME "no 16-bit sound");
return 0;
}
/* Cookie MCSN present ? */
if (Getcookie(C_McSn, (long *) &cookie_mcsn) != C_FOUND) {
SDL_SetError(DEBUG_NAME "no MCSN audio");
return 0;
}
return (1); /* We don't use SDL threaded audio */
/* Check if interrupt at end of replay */
if (cookie_mcsn->pint == 0) {
SDL_SetError(DEBUG_NAME "no interrupt at end of replay");
return 0;
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
SDL_SetError(DEBUG_NAME "audio locked by other application");
return 0;
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
/* Set the function pointers */
impl->OpenDevice = MINTMCSN_OpenDevice;
impl->CloseDevice = MINTMCSN_CloseDevice;
impl->LockAudio = MINTMCSN_LockAudio;
impl->UnlockAudio = MINTMCSN_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->SkipMixerLock = 1;
return 1;
}
AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver", MINTMCSN_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -59,8 +59,9 @@
/*--- Static variables ---*/
static unsigned long cookie_snd, cookie_mch;
static cookie_stfa_t *cookie_stfa;
static unsigned long cookie_snd = 0;
static unsigned long cookie_mch = 0;
static cookie_stfa_t *cookie_stfa = NULL;
static const int freqs[16] = {
4995, 6269, 7493, 8192,
......@@ -69,157 +70,66 @@ static const int freqs[16] = {
30720, 32336, 43885, 49152
};
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
/*--- Audio driver bootstrap functions ---*/
static int
Audio_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return (0);
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Cookie STFA present ? */
if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
DEBUG_PRINT((DEBUG_NAME "no STFA audio\n"));
return (0);
}
SDL_MintAudio_stfa = cookie_stfa;
DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
MINTSTFA_LockDevice(_THIS)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_STFA_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver",
Audio_Available, Audio_CreateDevice
};
static void
Mint_LockAudio(_THIS)
{
void *oldpile;
/* Stop replay */
oldpile = (void *) Super(0);
void *oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
Super(oldpile);
}
static void
Mint_UnlockAudio(_THIS)
MINTSTFA_UnlockDevice(_THIS)
{
void *oldpile;
/* Restart replay */
oldpile = (void *) Super(0);
void *oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT;
Super(oldpile);
}
static void
Mint_CloseAudio(_THIS)
MINTSTFA_CloseDevice(_THIS)
{
void *oldpile;
/* Stop replay */
oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
Super(oldpile);
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
if (this->hidden != NULL) {
/* Stop replay */
void *oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
Super(oldpile);
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
MINTSTFA_CheckAudio(_THIS)
{
int i;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (SDL_AUDIO_BITSIZE(spec->format) > 16) {
spec->format = AUDIO_S16SYS; /* clamp out int32/float32 ... */
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (SDL_AUDIO_BITSIZE(this->spec.format) > 16) {
this->spec.format = AUDIO_S16SYS; /* clamp out int32/float32 ... */
}
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
if (this->spec.channels > 2) {
this->spec.channels = 2; /* no more than stereo! */
}
/* Check formats available */
......@@ -237,29 +147,25 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
}
#endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0;
}
static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
MINTSTFA_InitAudio(_THIS)
{
void *buffer;
void *oldpile;
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
oldpile = (void *) Super(0);
void *buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
void *oldpile = (void *) Super(0);
/* Stop replay */
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
......@@ -267,22 +173,22 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */
cookie_stfa->sound_control =
MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if (SDL_AUDIO_BITSIZE(spec->format) == 8) {
if (SDL_AUDIO_BITSIZE(this->spec.format) == 8) {
cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
}
if (spec->channels == 2) {
if (this->spec.channels == 2) {
cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_MONO;
}
if (SDL_AUDIO_ISSIGNED(spec->format) != 0) {
if (SDL_AUDIO_ISSIGNED(this->spec.format) != 0) {
cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
}
if (SDL_AUDIO_ISBIGENDIAN(spec->format) != 0) {
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format) != 0) {
cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
......@@ -290,7 +196,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */
cookie_stfa->sound_start = (unsigned long) buffer;
cookie_stfa->sound_end = (unsigned long) (buffer + spec->size);
cookie_stfa->sound_end = (unsigned long) (buffer + this->spec.size);
/* Set interrupt */
cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
......@@ -304,29 +210,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
}
static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
MINTSTFA_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) {
return -1;
if (MINTSTFA_CheckAudio(this) == -1) {
return 0;
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
SDL_OutOfMemory()
SDL_free(this->hidden);
this->hidden = NULL;
return 0;
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
SDL_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
SDL_MintAudio_audiosize = spec->size;
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
......@@ -337,9 +254,49 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
MINTSTFA_InitAudio(this);
return (1); /* We don't use threaded audio */
return 1; /* good to go. */
}
static int
MINTSTFA_Init(SDL_AudioDriverImpl *impl)
{
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Cookie STFA present ? */
if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
SDL_SetError(DEBUG_NAME "no STFA audio");
return (0);
}
SDL_MintAudio_stfa = cookie_stfa;
DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
/* Set the function pointers */
impl->OpenDevice = MINTSTFA_OpenDevice;
impl->CloseDevice = MINTSTFA_CloseDevice;
impl->LockAudio = MINTSTFA_LockAudio;
impl->UnlockAudio = MINTSTFA_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->SkipMixerLock = 1;
return 1;
}
AudioBootStrap MINTAUDIO_STFA_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver", MINTSTFA_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -60,147 +60,50 @@
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static unsigned long cookie_snd;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
/*--- Audio driver bootstrap functions ---*/
static int
Audio_Available(void)
{
unsigned long dummy;
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND); */
SDL_MintAudio_mint_present = SDL_FALSE;
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return (0);
}
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return (0);
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return (0);
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return (0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver",
Audio_Available, Audio_CreateDevice
};
static unsigned long cookie_snd = 0;
static void
Mint_LockAudio(_THIS)
MINTXBIOS_LockDevice(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void
Mint_UnlockAudio(_THIS)
MINTXBIOS_UnlockDevice(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
}
static void
Mint_CloseAudio(_THIS)
MINTXBIOS_CloseDevice(_THIS)
{
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (this->hidden != NULL) {
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
/* Unlock sound system */
Unlocksnd();
SDL_free(this->hidden);
this->hidden = NULL;
}
}
/* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
......@@ -269,7 +172,7 @@ Devconnect2(int src, int dst, int sclk, int pre)
}
static void
Mint_CheckExternalClock(_THIS)
MINTXBIOS_CheckExternalClock(_THIS)
{
#define SIZE_BUF_CLOCK_MEASURE (44100/10)
......@@ -355,33 +258,33 @@ Mint_CheckExternalClock(_THIS)
}
static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
MINTXBIOS_CheckAudio(_THIS)
{
int i;
Uint32 extclock;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
spec->format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
this->spec.format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
/* clamp out int32/float32 */
if (SDL_AUDIO_BITSIZE(spec->format) >= 16) {
spec->format = AUDIO_S16MSB; /* Audio is always big endian */
spec->channels = 2; /* 16 bits always stereo */
} else if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
if (SDL_AUDIO_BITSIZE(this->spec.format) >= 16) {
this->spec.format = AUDIO_S16MSB; /* Audio is always big endian */
this->spec.channels = 2; /* 16 bits always stereo */
} else if (this->spec.channels > 2) {
this->spec.channels = 2; /* no more than stereo! */
}
MINTAUDIO_freqcount = 0;
/* Add external clocks if present */
Mint_CheckExternalClock(this);
MINTXBIOS_CheckExternalClock(this);
/* Standard clocks */
for (i = 1; i < 12; i++) {
......@@ -404,22 +307,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
}
#endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0;
}
static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
MINTXBIOS_InitAudio(_THIS)
{
int channels_mode, dmaclock, prediv;
void *buffer;
......@@ -436,9 +339,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */
channels_mode = STEREO16;
switch (SDL_AUDIO_BITSIZE(spec->format)) {
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8:
if (spec->channels == 2) {
if (this->spec.channels == 2) {
channels_mode = STEREO8;
} else {
channels_mode = MONO8;
......@@ -461,7 +364,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
......@@ -485,35 +388,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
}
static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
MINTXBIOS_OpenDevice(_THIS, const char *devname, int iscapture)
{
/* Lock sound system */
if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return (-1);
SDL_SetError("MINTXBIOS_OpenAudio: Audio system already in use");
return 0;
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) {
return -1;
if (MINTXBIOS_CheckAudio(this) == -1) {
return 0;
}
SDL_CalculateAudioSpec(spec);
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_CalculateAudioSpec(&this->spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
SDL_free(this->hidden);
this->hidden = NULL;
SDL_OutOfMemory();
return 0;
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
SDL_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
SDL_MintAudio_audiosize = spec->size;
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
......@@ -524,9 +438,58 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
MINTXBIOS_InitAudio(this);
return 1; /* good to go. */
}
static int
MINTXBIOS_Init(SDL_AudioDriverImpl *impl)
{
unsigned long dummy = 0;
/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND); */
SDL_MintAudio_mint_present = SDL_FALSE;
return (1); /* We don't use SDL threaded audio */
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return (0);
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT) == 0) {
SDL_SetError(DEBUG_NAME "no 16-bit sound");
return (0);
}
/* Check if audio is lockable */
if (Locksnd() != 1) {
SDL_SetError(DEBUG_NAME "audio locked by other application");
return (0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
/* Set the function pointers */
impl->OpenDevice = MINTXBIOS_OpenDevice;
impl->CloseDevice = MINTXBIOS_CloseDevice;
impl->LockAudio = MINTXBIOS_LockAudio;
impl->UnlockAudio = MINTXBIOS_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->SkipMixerLock = 1;
return 1;
}
AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver", MINTXBIOS_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -31,70 +31,6 @@
static BOOL inUse[NUM_BUFFERS];
/* Audio driver functions */
static int MME_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void MME_WaitAudio(_THIS);
static Uint8 *MME_GetAudioBuf(_THIS);
static void MME_PlayAudio(_THIS);
static void MME_WaitDone(_THIS);
static void MME_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
if (device) {
if (device->hidden) {
SDL_free(device->hidden);
device->hidden = NULL;
}
SDL_free(device);
device = NULL;
}
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = MME_OpenAudio;
this->WaitAudio = MME_WaitAudio;
this->PlayAudio = MME_PlayAudio;
this->GetAudioBuf = MME_GetAudioBuf;
this->WaitDone = MME_WaitDone;
this->CloseAudio = MME_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MMEAUDIO_bootstrap = {
"waveout", "Tru64 MME WaveOut",
Audio_Available, Audio_CreateDevice
};
static void
SetMMerror(char *function, MMRESULT code)
{
......@@ -108,7 +44,7 @@ SetMMerror(char *function, MMRESULT code)
}
static void CALLBACK
MME_CALLBACK(HWAVEOUT hwo,
MME_Callback(HWAVEOUT hwo,
UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2)
{
WAVEHDR *wp = (WAVEHDR *) dwParam1;
......@@ -118,116 +54,137 @@ MME_CALLBACK(HWAVEOUT hwo,
}
static int
MME_OpenAudio(_THIS, SDL_AudioSpec * spec)
MME_OpenDevice(_THIS, const char *devname, int iscapture)
{
int valid_format = 0;
MMRESULT result;
Uint8 *mixbuf = NULL;
int i;
mixbuf = NULL;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set basic WAVE format parameters */
shm = mmeAllocMem(sizeof(*shm));
if (shm == NULL) {
SDL_SetError("Out of memory: shm");
return (-1);
this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
if (this->hidden->shm == NULL) {
MME_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
shm->sound = 0;
shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
SDL_memset(this->hidden->shm, '\0', sizeof (*this->hidden->shm));
this->hidden->shm->sound = 0;
this->hidden->shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
/* Determine the audio parameters from the AudioSpec */
switch (SDL_AUDIO_BITSIZE(spec->format)) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
shm->wFmt.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
shm->wFmt.wBitsPerSample = 16;
break;
case 32:
/* Signed 32 bit audio data */
spec->format = AUDIO_S32;
shm->wFmt.wBitsPerSample = 32;
break;
default:
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!valid_format && test_format;) {
valid_format = 1;
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
break;
default:
valid_format = 0;
test_format = SDL_NextAudioFormat();
}
}
if (!valid_format) {
MME_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return (-1);
return 0;
}
this->spec.format = test_format;
this->hidden->shm->wFmt.wBitsPerSample = SDL_AUDIO_BITSIZE(test_format);
/* !!! FIXME: Can this handle more than stereo? */
shm->wFmt.wf.nChannels = spec->channels;
shm->wFmt.wf.nSamplesPerSec = spec->freq;
shm->wFmt.wf.nBlockAlign =
shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
shm->wFmt.wf.nAvgBytesPerSec =
shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
this->hidden->shm->wFmt.wf.nBlockAlign =
this->hidden->shm->wFmt.wf.nChannels *
this->hidden->shm->wFmt.wBitsPerSample / 8;
this->hidden->shm->wFmt.wf.nAvgBytesPerSec =
this->hidden->shm->wFmt.wf.nSamplesPerSec *
this->hidden->shm->wFmt.wf.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
if (spec->samples < (spec->freq / 4))
spec->samples = ((spec->freq / 4) + 3) & ~3;
if (this->spec.samples < (this->spec.freq / 4))
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */
result = waveOutOpen(&(shm->sound),
result = waveOutOpen(&(this->hidden->shm->sound),
WAVE_MAPPER,
&(shm->wFmt.wf),
MME_CALLBACK,
&(this->hidden->shm->wFmt.wf),
MME_Callback,
NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
if (result != MMSYSERR_NOERROR) {
MME_CloseDevice(this);
SetMMerror("waveOutOpen()", result);
return (-1);
return 0;
}
/* Create the sound buffers */
mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (spec->size));
mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
if (mixbuf == NULL) {
SDL_SetError("Out of memory: mixbuf");
return (-1);
MME_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
this->hidden->mixbuf = mixbuf;
for (i = 0; i < NUM_BUFFERS; i++) {
shm->wHdr[i].lpData = &mixbuf[i * (spec->size)];
shm->wHdr[i].dwBufferLength = spec->size;
shm->wHdr[i].dwFlags = 0;
shm->wHdr[i].dwUser = i;
shm->wHdr[i].dwLoops = 0; /* loop control counter */
shm->wHdr[i].lpNext = NULL; /* reserved for driver */
shm->wHdr[i].reserved = 0;
this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
this->hidden->shm->wHdr[i].dwFlags = 0;
this->hidden->shm->wHdr[i].dwUser = i;
this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
this->hidden->shm->wHdr[i].lpNext = NULL; /* reserved for driver */
this->hidden->shm->wHdr[i].reserved = 0;
inUse[i] = FALSE;
}
next_buffer = 0;
return 0;
this->hidden->next_buffer = 0;
return 1;
}
static void
MME_WaitAudio(_THIS)
MME_WaitDevice(_THIS)
{
while (inUse[next_buffer]) {
while (inUse[this->hidden->next_buffer]) {
mmeWaitForCallbacks();
mmeProcessCallbacks();
}
}
static Uint8 *
MME_GetAudioBuf(_THIS)
MME_GetDeviceBuf(_THIS)
{
Uint8 *retval;
inUse[next_buffer] = TRUE;
retval = (Uint8 *) (shm->wHdr[next_buffer].lpData);
return retval;
void *retval = this->hidden->shm->wHdr[this->hidden->next_buffer].lpData;
inUse[this->hidden->next_buffer] = TRUE;
return (Uint8 *) retval;
}
static void
MME_PlayAudio(_THIS)
MME_PlayDevice(_THIS)
{
/* Queue it up */
waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
next_buffer = (next_buffer + 1) % NUM_BUFFERS;
waveOutWrite(this->hidden->shm->sound,
&(this->hidden->shm->wHdr[this->hidden->next_buffer]),
sizeof (WAVEHDR));
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
static void
......@@ -236,13 +193,13 @@ MME_WaitDone(_THIS)
MMRESULT result;
int i;
if (shm->sound) {
if (this->hidden->shm->sound) {
for (i = 0; i < NUM_BUFFERS; i++)
while (inUse[i]) {
mmeWaitForCallbacks();
mmeProcessCallbacks();
}
result = waveOutReset(shm->sound);
result = waveOutReset(this->hidden->shm->sound);
if (result != MMSYSERR_NOERROR)
SetMMerror("waveOutReset()", result);
mmeProcessCallbacks();
......@@ -250,29 +207,54 @@ MME_WaitDone(_THIS)
}
static void
MME_CloseAudio(_THIS)
MME_CloseDevice(_THIS)
{
MMRESULT result;
if (this->hidden != NULL) {
MMRESULT result;
if (mixbuf) {
result = mmeFreeBuffer(mixbuf);
if (result != MMSYSERR_NOERROR)
SetMMerror("mmeFreeBuffer", result);
mixbuf = NULL;
}
if (this->hidden->mixbuf) {
result = mmeFreeBuffer(this->hidden->mixbuf);
if (result != MMSYSERR_NOERROR)
SetMMerror("mmeFreeBuffer", result);
this->hidden->mixbuf = NULL;
}
if (shm) {
if (shm->sound) {
result = waveOutClose(shm->sound);
if (this->hidden->shm) {
if (this->hidden->shm->sound) {
result = waveOutClose(this->hidden->shm->sound);
if (result != MMSYSERR_NOERROR)
SetMMerror("waveOutClose()", result);
mmeProcessCallbacks();
}
result = mmeFreeMem(this->hidden->shm);
if (result != MMSYSERR_NOERROR)
SetMMerror("waveOutClose()", result);
mmeProcessCallbacks();
SetMMerror("mmeFreeMem()", result);
this->hidden->shm = NULL;
}
result = mmeFreeMem(shm);
if (result != MMSYSERR_NOERROR)
SetMMerror("mmeFreeMem()", result);
shm = NULL;
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
MME_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = MME_OpenDevice;
impl->WaitDevice = MME_WaitDevice;
impl->WaitDone = MME_WaitDone;
impl->PlayDevice = MME_PlayDevice;
impl->GetDeviceBuf = MME_GetDeviceBuf;
impl->CloseDevice = MME_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
return 1;
}
/* !!! FIXME: Windows "windib" driver is called waveout, too */
AudioBootStrap MMEAUDIO_bootstrap = {
"waveout", "Tru64 MME WaveOut", MME_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -23,12 +23,12 @@
/* Allow access to a raw mixing buffer */
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_mmeaudio_h
#define _SDL_mmeaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2
......@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
int next_buffer;
};
#define shm (this->hidden->shm)
#define mixbuf (this->hidden->mixbuf)
#define next_buffer (this->hidden->next_buffer)
/* Old variable names */
#endif /* _SDL_lowaudio_h */
#endif /* _SDL_mmeaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -32,106 +32,149 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_nasaudio.h"
/* The tag name used by artsc audio */
/* The tag name used by nas audio */
#define NAS_DRIVER_NAME "nas"
static struct SDL_PrivateAudioData *this2 = NULL;
/* Audio driver functions */
static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void NAS_WaitAudio(_THIS);
static void NAS_PlayAudio(_THIS);
static Uint8 *NAS_GetAudioBuf(_THIS);
static void NAS_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static void (*NAS_AuCloseServer)(AuServer *);
static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *);
static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *);
static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *);
static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *);
static void (*NAS_AuSetElements)
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
static void (*NAS_AuWriteElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
static AuServer *(*NAS_AuOpenServer)
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
static void *nas_handle = NULL;
static int
Audio_Available(void)
load_nas_sym(const char *fn, void **addr)
{
AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (!aud)
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
return 0;
AuCloseServer(aud);
}
return 1;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_NAS_SYM(x) \
if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
#else
#define SDL_NAS_SYM(x) NAS_##x = x
#endif
static int load_nas_syms(void)
{
SDL_free(device->hidden);
SDL_free(device);
SDL_NAS_SYM(AuCloseServer);
SDL_NAS_SYM(AuNextEvent);
SDL_NAS_SYM(AuDispatchEvent);
SDL_NAS_SYM(AuCreateFlow);
SDL_NAS_SYM(AuStartFlow);
SDL_NAS_SYM(AuSetElements);
SDL_NAS_SYM(AuWriteElement);
SDL_NAS_SYM(AuOpenServer);
SDL_NAS_SYM(AuRegisterEventHandler);
return 0;
}
#undef SDL_NAS_SYM
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
static void
UnloadNASLibrary(void)
{
if (nas_handle != NULL) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
static int
LoadNASLibrary(void)
{
int retval = 0;
if (nas_handle == NULL) {
nas_handle = SDL_LoadObject(nas_library);
if (nas_handle == NULL) {
/* Copy error string so we can use it in a new SDL_SetError(). */
char *origerr = SDL_GetError();
size_t len = SDL_strlen(origerr) + 1;
char *err = (char *) alloca(len);
SDL_strlcpy(err, origerr, len);
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
return retval;
}
/* Set the function pointers */
this->OpenAudio = NAS_OpenAudio;
this->WaitAudio = NAS_WaitAudio;
this->PlayAudio = NAS_PlayAudio;
this->GetAudioBuf = NAS_GetAudioBuf;
this->CloseAudio = NAS_CloseAudio;
#else
this->free = Audio_DeleteDevice;
static void
UnloadNASLibrary(void)
{
}
return this;
static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
}
AudioBootStrap NAS_bootstrap = {
NAS_DRIVER_NAME, "Network Audio System",
Audio_Available, Audio_CreateDevice
};
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
/* This function waits until it is possible to write a full sound buffer */
static void
NAS_WaitAudio(_THIS)
NAS_WaitDevice(_THIS)
{
while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev);
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
}
static void
NAS_PlayAudio(_THIS)
NAS_PlayDevice(_THIS)
{
while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
in the hope that some of them is LowWater events telling us more
of the buffer is free now than what we think. */
while (this->hidden->mixlen > this->hidden->buf_free) {
/*
* We think the buffer is full? Yikes! Ask the server for events,
* in the hope that some of them is LowWater events telling us more
* of the buffer is free now than what we think.
*/
AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev);
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */
AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
this->hidden->written += this->hidden->mixlen;
......@@ -142,21 +185,25 @@ NAS_PlayAudio(_THIS)
}
static Uint8 *
NAS_GetAudioBuf(_THIS)
NAS_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
NAS_CloseAudio(_THIS)
NAS_CloseDevice(_THIS)
{
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->aud) {
AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->aud) {
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
}
SDL_free(this->hidden);
this2 = this->hidden = NULL;
}
}
......@@ -221,6 +268,7 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
static AuDeviceID
find_device(_THIS, int nch)
{
/* These "Au" things are all macros, not functions... */
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
......@@ -233,46 +281,53 @@ find_device(_THIS, int nch)
}
static int
NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
NAS_OpenDevice(_THIS, const char *devname, int iscapture)
{
AuElement elms[3];
int buffer_size;
SDL_AudioFormat test_format, format;
this->hidden->mixbuf = NULL;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
format = sdlformat_to_auformat(test_format);
if (format == AuNone) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
SDL_SetError("Couldn't find any hardware audio formats");
return (-1);
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find any hardware audio formats");
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (this->hidden->aud == 0) {
SDL_SetError("Couldn't open connection to NAS server");
return (-1);
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't open connection to NAS server");
return 0;
}
this->hidden->dev = find_device(this, spec->channels);
this->hidden->dev = find_device(this, this->spec.channels);
if ((this->hidden->dev == AuNone)
|| (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
SDL_SetError("Couldn't find a fitting playback device on NAS server");
return (-1);
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
NAS_CloseDevice(this);
SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
return 0;
}
buffer_size = spec->freq;
buffer_size = this->spec.freq;
if (buffer_size < 4096)
buffer_size = 4096;
......@@ -280,35 +335,70 @@ NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
this2 = this->hidden;
AuMakeElementImportClient(elms, spec->freq, format, spec->channels,
AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels,
AuTrue, buffer_size, buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq,
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
AuUnlimitedSamples, 0, NULL);
AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
NULL);
AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
AuTrue, 2, elms, NULL);
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return (-1);
NAS_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
this->hidden->parent = getpid();
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return (0);
return 1;
}
static void
NAS_Deinitialize(void)
{
UnloadNASLibrary();
}
static int
NAS_Init(SDL_AudioDriverImpl *impl)
{
if (LoadNASLibrary() < 0) {
return 0;
} else {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (aud == NULL) {
SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
return 0;
}
NAS_AuCloseServer(aud);
}
/* Set the function pointers */
impl->OpenDevice = NAS_OpenDevice;
impl->PlayDevice = NAS_PlayDevice;
impl->WaitDevice = NAS_WaitDevice;
impl->GetDeviceBuf = NAS_GetDeviceBuf;
impl->CloseDevice = NAS_CloseDevice;
impl->Deinitialize = NAS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
return 1;
}
AudioBootStrap NAS_bootstrap = {
NAS_DRIVER_NAME, "Network Audio System", NAS_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -37,7 +37,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
AuFlowID flow;
AuDeviceID dev;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
......@@ -60,4 +57,5 @@ struct SDL_PrivateAudioData
int buf_free;
};
#endif /* _SDL_nasaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -69,13 +69,13 @@ struct BuggyCards buggycards[QSA_WA_CARDS] = {
{"Vortex 8830", QSA_MMAP_WORKAROUND},
};
/* Audio driver functions */
static void NTO_ThreadInit(_THIS);
static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void NTO_WaitAudio(_THIS);
static void NTO_PlayAudio(_THIS);
static Uint8 *NTO_GetAudioBuf(_THIS);
static void NTO_CloseAudio(_THIS);
static inline void
NTO_SetError(const char *fn, int rval)
{
SDL_SetError("NTO: %s failed: %s", fn, snd_strerror(rval));
}
/* card names check to apply the workarounds */
static int
......@@ -84,7 +84,7 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
char scardname[33];
int it;
if (snd_card_get_name(cardno, scardname, 32) < 0) {
if (snd_card_get_name(this->hidden->cardno, scardname, 32) < 0) {
return 0;
}
......@@ -102,11 +102,10 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
static void
NTO_ThreadInit(_THIS)
{
int status;
struct sched_param param;
int status = SchedGet(0, 0, &param);
/* increasing default 10 priority to 25 to avoid jerky sound */
status = SchedGet(0, 0, &param);
param.sched_priority = param.sched_curpriority + 15;
status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
}
......@@ -130,111 +129,26 @@ NTO_InitAudioParams(snd_pcm_channel_params_t * cpars)
cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
}
static int
NTO_AudioAvailable(void)
{
/* See if we can open a nonblocking channel.
Return value '1' means we can.
Return value '0' means we cannot. */
int available;
int rval;
snd_pcm_t *handle;
available = 0;
handle = NULL;
rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
if (rval >= 0) {
available = 1;
if ((rval = snd_pcm_close(handle)) < 0) {
SDL_SetError
("NTO_AudioAvailable(): snd_pcm_close failed: %s\n",
snd_strerror(rval));
available = 0;
}
} else {
SDL_SetError
("NTO_AudioAvailable(): there are no available audio devices.\n");
}
return (available);
}
static void
NTO_DeleteAudioDevice(SDL_AudioDevice * device)
{
if ((device) && (device->hidden)) {
SDL_free(device->hidden);
}
if (device) {
SDL_free(device);
}
}
static SDL_AudioDevice *
NTO_CreateAudioDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, sizeof(SDL_AudioDevice));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(struct SDL_PrivateAudioData));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
audio_handle = NULL;
/* Set the function pointers */
this->ThreadInit = NTO_ThreadInit;
this->OpenAudio = NTO_OpenAudio;
this->WaitAudio = NTO_WaitAudio;
this->PlayAudio = NTO_PlayAudio;
this->GetAudioBuf = NTO_GetAudioBuf;
this->CloseAudio = NTO_CloseAudio;
this->free = NTO_DeleteAudioDevice;
return this;
}
AudioBootStrap QNXNTOAUDIO_bootstrap = {
DRIVER_NAME, "QNX6 QSA-NTO Audio",
NTO_AudioAvailable,
NTO_CreateAudioDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
NTO_WaitAudio(_THIS)
NTO_WaitDevice(_THIS)
{
fd_set wfds;
int selectret;
FD_ZERO(&wfds);
FD_SET(audio_fd, &wfds);
FD_SET(this->hidden->audio_fd, &wfds);
do {
selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL);
selectret = select(this->hidden->audio_fd+1, NULL, &wfds, NULL, NULL);
switch (selectret) {
case -1:
case 0:
SDL_SetError("NTO_WaitAudio(): select() failed: %s\n",
strerror(errno));
SDL_SetError("NTO: select() failed: %s\n", strerror(errno));
return;
default:
if (FD_ISSET(audio_fd, &wfds)) {
if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
return;
}
break;
......@@ -244,22 +158,24 @@ NTO_WaitAudio(_THIS)
}
static void
NTO_PlayAudio(_THIS)
NTO_PlayDevice(_THIS)
{
snd_pcm_channel_status_t cstatus;
int written, rval;
int towrite;
void *pcmbuffer;
if (!this->enabled) {
if ((!this->enabled) || (!this->hidden)) {
return;
}
towrite = this->spec.size;
pcmbuffer = pcm_buf;
pcmbuffer = this->hidden->pcm_buf;
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do {
written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
written = snd_pcm_plugin_write(this->hidden->audio_handle,
pcmbuffer, towrite);
if (written != towrite) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
/* Let a little CPU time go by and try to write again */
......@@ -268,33 +184,28 @@ NTO_PlayAudio(_THIS)
towrite -= written;
pcmbuffer += written * this->spec.channels;
continue;
} else {
if ((errno == EINVAL) || (errno == EIO)) {
SDL_memset(&cstatus, 0, sizeof(cstatus));
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
if ((rval =
snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) {
SDL_SetError
("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n",
snd_strerror(rval));
} else if ((errno == EINVAL) || (errno == EIO)) {
SDL_memset(&cstatus, 0, sizeof (cstatus));
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
rval = snd_pcm_plugin_status(this->hidden->audio_handle,
&cstatus);
if (rval < 0) {
NTO_SetError("snd_pcm_plugin_status", rval);
return;
}
if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
(cstatus.status == SND_PCM_STATUS_READY)) {
rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
if (rval < 0) {
NTO_SetError("snd_pcm_plugin_prepare", rval);
return;
}
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN)
|| (cstatus.status == SND_PCM_STATUS_READY)) {
if ((rval =
snd_pcm_plugin_prepare(audio_handle,
SND_PCM_CHANNEL_PLAYBACK))
< 0) {
SDL_SetError
("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n",
snd_strerror(rval));
return;
}
}
continue;
} else {
return;
}
continue;
} else {
return;
}
} else {
/* we wrote all remaining data */
......@@ -308,77 +219,74 @@ NTO_PlayAudio(_THIS)
if (towrite != 0) {
this->enabled = 0;
}
return;
}
static Uint8 *
NTO_GetAudioBuf(_THIS)
NTO_GetDeviceBuf(_THIS)
{
return pcm_buf;
return this->hidden->pcm_buf;
}
static void
NTO_CloseAudio(_THIS)
NTO_CloseDevice(_THIS)
{
int rval;
this->enabled = 0;
if (audio_handle != NULL) {
if ((rval =
snd_pcm_plugin_flush(audio_handle,
SND_PCM_CHANNEL_PLAYBACK)) < 0) {
SDL_SetError
("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n",
snd_strerror(rval));
return;
if (this->hidden != NULL) {
if (this->hidden->audio_handle != NULL) {
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
snd_pcm_close(this->hidden->audio_handle);
this->hidden->audio_handle = NULL;
}
if ((rval = snd_pcm_close(audio_handle)) < 0) {
SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",
snd_strerror(rval));
return;
if (this->hidden->pcm_buf != NULL) {
SDL_FreeAudioMem(this->hidden->pcm_buf);
this->hidden->pcm_buf = NULL;
}
audio_handle = NULL;
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
NTO_OpenDevice(_THIS, const char *devname, int iscapture)
{
int rval;
int format;
SDL_AudioFormat test_format;
int found;
audio_handle = NULL;
this->enabled = 0;
int rval = 0;
int format = 0;
SDL_AudioFormat test_format = 0;
int found = 0;
snd_pcm_channel_setup_t csetup;
snd_pcm_channel_params_t cparams;
if (pcm_buf != NULL) {
SDL_FreeAudioMem(pcm_buf);
pcm_buf = NULL;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* initialize channel transfer parameters to default */
NTO_InitAudioParams(&cparams);
/* Open the audio device */
rval =
snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
rval = snd_pcm_open_preferred(&this->hidden->audio_handle,
&this->hidden->cardno,
&this->hidden->deviceno, OPEN_FLAGS);
if (rval < 0) {
SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n",
snd_strerror(rval));
return (-1);
NTO_CloseDevice(this);
NTO_SetError("snd_pcm_open", rval);
return 0;
}
if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
/* enable count status parameter */
if ((rval =
snd_pcm_plugin_set_disable(audio_handle,
PLUGIN_DISABLE_MMAP)) < 0) {
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n",
snd_strerror(rval));
return (-1);
rval = snd_pcm_plugin_set_disable(this->hidden->audio_handle,
PLUGIN_DISABLE_MMAP);
if (rval < 0) {
NTO_CloseDevice(this);
NTO_SetError("snd_pcm_plugin_set_disable", rval);
return 0;
}
}
......@@ -387,7 +295,7 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
found = 0;
for (test_format = SDL_FirstAudioFormat(spec->format); !found;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
/* if match found set format to equivalent ALSA format */
switch (test_format) {
case AUDIO_U8:
......@@ -441,86 +349,115 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* assumes test_format not 0 on success */
if (test_format == 0) {
SDL_SetError
("NTO_OpenAudio(): Couldn't find any hardware audio formats");
return (-1);
NTO_CloseDevice(this);
SDL_SetError("NTO: Couldn't find any hardware audio formats");
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
/* Set the audio format */
cparams.format.format = format;
/* Set mono or stereo audio (currently only two channels supported) */
cparams.format.voices = spec->channels;
cparams.format.voices = this->spec.channels;
/* Set rate */
cparams.format.rate = spec->freq;
cparams.format.rate = this->spec.freq;
/* Setup the transfer parameters according to cparams */
rval = snd_pcm_plugin_params(audio_handle, &cparams);
rval = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
if (rval < 0) {
SDL_SetError
("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n",
snd_strerror(rval));
return (-1);
NTO_CloseDevice(this);
NTO_SetError("snd_pcm_channel_params", rval);
return 0;
}
/* Make sure channel is setup right one last time */
SDL_memset(&csetup, 0x00, sizeof(csetup));
SDL_memset(&csetup, '\0', sizeof (csetup));
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) {
SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
return -1;
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
NTO_CloseDevice(this);
SDL_SetError("NTO: Unable to setup playback channel\n");
return 0;
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
pcm_len = spec->size;
this->hidden->pcm_len = this->spec.size;
if (pcm_len == 0) {
pcm_len =
csetup.buf.block.frag_size * spec->channels *
if (this->hidden->pcm_len == 0) {
this->hidden->pcm_len =
csetup.buf.block.frag_size * this->spec.channels *
(snd_pcm_format_width(format) / 8);
}
/* Allocate memory to the audio buffer and initialize with silence (Note that
buffer size must be a multiple of fragment size, so find closest multiple)
/*
* Allocate memory to the audio buffer and initialize with silence
* (Note that buffer size must be a multiple of fragment size, so find
* closest multiple)
*/
pcm_buf = (Uint8 *) SDL_AllocAudioMem(pcm_len);
if (pcm_buf == NULL) {
SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
return (-1);
this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
if (this->hidden->pcm_buf == NULL) {
NTO_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(pcm_buf, spec->silence, pcm_len);
SDL_memset(this->hidden->pcm_buf,this->spec.silence,this->hidden->pcm_len);
/* get the file descriptor */
if ((audio_fd =
snd_pcm_file_descriptor(audio_handle,
SND_PCM_CHANNEL_PLAYBACK)) < 0) {
SDL_SetError
("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n",
snd_strerror(rval));
return (-1);
this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
if (this->hidden->audio_fd < 0) {
NTO_CloseDevice(this);
NTO_SetError("snd_pcm_file_descriptor", rval);
return 0;
}
/* Trigger audio playback */
rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
if (rval < 0) {
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",
snd_strerror(rval));
return (-1);
NTO_CloseDevice(this);
NTO_SetError("snd_pcm_plugin_prepare", rval);
return 0;
}
this->enabled = 1;
/* We're really ready to rock and roll. :-) */
return 1;
}
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're really ready to rock and roll. :-) */
return (0);
static int
NTO_Init(SDL_AudioDriverImpl *impl)
{
/* See if we can open a nonblocking channel. */
snd_pcm_t *handle = NULL;
int rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
if (rval < 0) {
SDL_SetError("NTO: couldn't open preferred audio device");
return 0;
}
if ((rval = snd_pcm_close(handle)) < 0) {
SDL_SetError("NTO: couldn't close test audio device");
return 0;
}
/* Set the function pointers */
impl->OpenDevice = NTO_OpenDevice;
impl->ThreadInit = NTO_ThreadInit;
impl->WaitDevice = NTO_WaitDevice;
impl->PlayDevice = NTO_PlayDevice;
impl->GetDeviceBuf = NTO_GetDeviceBuf;
impl->CloseDevice = NTO_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
return 1;
}
AudioBootStrap QNXNTOAUDIO_bootstrap = {
DRIVER_NAME, "QNX6 QSA-NTO Audio", NTO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -47,23 +47,7 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */
Uint8 *pcm_buf;
Uint32 pcm_len;
/* QSA parameters */
snd_pcm_channel_status_t cstatus;
snd_pcm_channel_params_t cparams;
snd_pcm_channel_setup_t csetup;
};
#define cardno (this->hidden->cardno)
#define deviceno (this->hidden->deviceno)
#define audio_handle (this->hidden->audio_handle)
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define pcm_buf (this->hidden->pcm_buf)
#define pcm_len (this->hidden->pcm_len)
#define cstatus (this->hidden->cstatus)
#define cparams (this->hidden->cparams)
#define csetup (this->hidden->csetup)
#endif /* __SDL_NTO_AUDIO_H__ */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -30,16 +30,17 @@
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_stdinc.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_paudio.h"
#define DEBUG_AUDIO 1
#define DEBUG_AUDIO 0
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
* I guess nobody ever uses audio... Shame over AIX header files. */
......@@ -48,94 +49,95 @@
#include <sys/audio.h>
/* The tag name used by paud audio */
#define Paud_DRIVER_NAME "paud"
#define PAUDIO_DRIVER_NAME "paud"
/* Open the audio device for playback, and don't block if busy */
/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
#define OPEN_FLAGS O_WRONLY
/* Audio driver functions */
static int Paud_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void Paud_WaitAudio(_THIS);
static void Paud_PlayAudio(_THIS);
static Uint8 *Paud_GetAudioBuf(_THIS);
static void Paud_CloseAudio(_THIS);
/* Get the name of the audio device we use for output */
/* Audio driver bootstrap functions */
#ifndef _PATH_DEV_DSP
#define _PATH_DEV_DSP "/dev/%caud%c/%c"
#endif
static char devsettings[][3] = {
{'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
{'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
{'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
{'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
{'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
{'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
{'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
{'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
{'\0', '\0', '\0'}
};
static int
Audio_Available(void)
OpenUserDefinedDevice(char *path, int maxlen, int flags)
{
const char *audiodev;
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
available = 1;
close(fd);
/* Figure out what our audio device is */
if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
audiodev = SDL_getenv("AUDIODEV");
}
return (available);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
if (audiodev == NULL) {
return -1;
}
fd = open(audiodev, flags, 0);
if (path != NULL) {
SDL_strlcpy(path, audiodev, maxlen);
path[maxlen - 1] = '\0';
}
return fd;
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static int
OpenAudioPath(char *path, int maxlen, int flags, int classic)
{
SDL_AudioDevice *this;
struct stat sb;
int cycle = 0;
int fd = OpenUserDefinedDevice(path, maxlen, flags);
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (fd != -1) {
return fd;
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
/* !!! FIXME: do we really need a table here? */
while (devsettings[cycle][0] != '\0') {
char audiopath[1024];
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
_PATH_DEV_DSP,
devsettings[cycle][0],
devsettings[cycle][1], devsettings[cycle][2]);
if (stat(audiopath, &sb) == 0) {
fd = open(audiopath, flags, 0);
if (fd > 0) {
if (path != NULL) {
SDL_strlcpy(path, audiopath, maxlen);
}
return fd;
}
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = Paud_OpenAudio;
this->WaitAudio = Paud_WaitAudio;
this->PlayAudio = Paud_PlayAudio;
this->GetAudioBuf = Paud_GetAudioBuf;
this->CloseAudio = Paud_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
return -1;
}
AudioBootStrap Paud_bootstrap = {
Paud_DRIVER_NAME, "AIX Paudio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
Paud_WaitAudio(_THIS)
PAUDIO_WaitDevice(_THIS)
{
fd_set fdset;
/* See if we need to use timed audio synchronization */
if (frame_ticks) {
if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
......@@ -145,9 +147,9 @@ Paud_WaitAudio(_THIS)
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
FD_SET(this->hidden->audio_fd, &fdset);
if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't get audio buffer information\n");
#endif
......@@ -168,7 +170,7 @@ Paud_WaitAudio(_THIS)
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) {
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
/*
......@@ -179,7 +181,7 @@ Paud_WaitAudio(_THIS)
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
......@@ -191,13 +193,15 @@ Paud_WaitAudio(_THIS)
}
static void
Paud_PlayAudio(_THIS)
PAUDIO_PlayDevice(_THIS)
{
int written;
int written = 0;
const Uint8 *mixbuf = this->hidden->mixbuf;
const size_t mixlen = this->hidden->mixlen;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
written = write(this->hidden->audio_fd, mixbuf, mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
......@@ -206,8 +210,8 @@ Paud_PlayAudio(_THIS)
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
......@@ -220,28 +224,34 @@ Paud_PlayAudio(_THIS)
}
static Uint8 *
Paud_GetAudioBuf(_THIS)
PAUDIO_GetDeviceBuf(_THIS)
{
return mixbuf;
return this->hidden->mixbuf;
}
static void
Paud_CloseAudio(_THIS)
PAUDIO_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
{
const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
char audiodev[1024];
const char *err = NULL;
int format;
int bytes_per_sample;
SDL_AudioFormat test_format;
......@@ -250,32 +260,40 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
audio_status paud_status;
audio_control paud_control;
audio_change paud_change;
int fd = -1;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if (audio_fd < 0) {
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
this->hidden->audio_fd = fd;
if (fd < 0) {
PAUDIO_CloseDevice(this);
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return -1;
return 0;
}
/*
* We can't set the buffer size - just ask the device for the maximum
* that we can have.
*/
if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
PAUDIO_CloseDevice(this);
SDL_SetError("Couldn't get audio buffer information");
return -1;
return 0;
}
mixbuf = NULL;
if (spec->channels > 1)
spec->channels = 2;
if (this->spec.channels > 1)
this->spec.channels = 2;
else
spec->channels = 1;
this->spec.channels = 1;
/*
* Fields in the audio_init structure:
......@@ -322,14 +340,14 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
* paud.position_resolution; * smallest increment for position
*/
paud_init.srate = spec->freq;
paud_init.srate = this->spec.freq;
paud_init.mode = PCM;
paud_init.operation = PLAY;
paud_init.channels = spec->channels;
paud_init.channels = this->spec.channels;
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
......@@ -382,31 +400,32 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif
PAUDIO_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return -1;
return 0;
}
spec->format = test_format;
this->spec.format = test_format;
/*
* We know the buffer size and the max number of subsequent writes
* that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway.
* that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway.
*
* We calculate spec->samples like this because SDL_CalculateAudioSpec()
* will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
* into spec->size in return.
* We calculate this->spec.samples like this because
* SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
* (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
*/
if (paud_bufinfo.request_buf_cap == 1) {
spec->samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / spec->channels;
this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / this->spec.channels;
} else {
spec->samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / spec->channels / 2;
this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / this->spec.channels / 2;
}
paud_init.bsize = bytes_per_sample * spec->channels;
paud_init.bsize = bytes_per_sample * this->spec.channels;
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/*
* The AIX paud device init can't modify the values of the audio_init
......@@ -416,47 +435,44 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
* /dev/paud supports all of the encoding formats, so we don't need
* to do anything like reopening the device, either.
*/
if (ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0) {
if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
switch (paud_init.rc) {
case 1:
SDL_SetError
("Couldn't set audio format: DSP can't do play requests");
return -1;
err = "Couldn't set audio format: DSP can't do play requests";
break;
case 2:
SDL_SetError
("Couldn't set audio format: DSP can't do record requests");
return -1;
err = "Couldn't set audio format: DSP can't do record requests";
break;
case 4:
SDL_SetError("Couldn't set audio format: request was invalid");
return -1;
err = "Couldn't set audio format: request was invalid";
break;
case 5:
SDL_SetError
("Couldn't set audio format: conflict with open's flags");
return -1;
err = "Couldn't set audio format: conflict with open's flags";
break;
case 6:
SDL_SetError
("Couldn't set audio format: out of DSP MIPS or memory");
return -1;
err = "Couldn't set audio format: out of DSP MIPS or memory";
break;
default:
SDL_SetError
("Couldn't set audio format: not documented in sys/audio.h");
return -1;
err = "Couldn't set audio format: not documented in sys/audio.h";
break;
}
}
if (err != NULL) {
PAUDIO_CloseDevice(this);
SDL_SetError("Paudio: %s", err);
return 0;
}
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return -1;
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
PAUDIO_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/*
* Set some paramters: full volume, first speaker that we can find.
......@@ -475,7 +491,7 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char *) &paud_change;
if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) {
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't change audio display settings\n");
#endif
......@@ -487,29 +503,49 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
*/
paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0;
if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) {
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
PAUDIO_CloseDevice(this);
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't start audio play\n");
#endif
SDL_SetError("Can't start audio play");
return -1;
return 0;
}
/* Check to see if we need to use select() workaround */
{
char *workaround;
workaround = SDL_getenv("SDL_DSP_NOSELECT");
if (workaround) {
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
}
if (workaround != NULL) {
this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
}
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return 0;
return 1;
}
static int
PAUDIO_Init(SDL_AudioDriverImpl *impl)
{
int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd < 0) {
SDL_SetError("PAUDIO: Couldn't open audio device");
return 0;
}
close(fd);
/* Set the function pointers */
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->PlayDevice = DSP_WaitDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
return 1;
}
AudioBootStrap PAUDIO_bootstrap = {
PAUDIO_DRIVER_NAME, "AIX Paudio", PAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -34,9 +34,6 @@ struct SDL_PrivateAudioData
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
......@@ -47,13 +44,5 @@ struct SDL_PrivateAudioData
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_paudaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
/* I'm gambling no one uses this audio backend...we'll see who emails. :) */
#error this code has not been updated for SDL 1.3.
#error if no one emails icculus at icculus.org and tells him that this
#error code is needed, this audio backend will eventually be removed from SDL.
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
......@@ -116,7 +121,7 @@ Audio_CreateDevice(int devindex)
AudioBootStrap SUNAUDIO_bootstrap = {
"audio", "UNIX /dev/audio interface",
Audio_Available, Audio_CreateDevice
Audio_Available, Audio_CreateDevice, 0
};
#ifdef DEBUG_AUDIO
......
......@@ -21,12 +21,12 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_sunaudio_h
#define _SDL_sunaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......@@ -53,5 +53,6 @@ struct SDL_PrivateAudioData
#define fragsize (this->hidden->fragsize)
#define frequency (this->hidden->frequency)
#endif /* _SDL_lowaudio_h */
#endif /* _SDL_sunaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
/* I'm gambling no one uses this audio backend...we'll see who emails. :) */
#error this code has not been updated for SDL 1.3.
#error if no one emails icculus at icculus.org and tells him that this
#error code is needed, this audio backend will eventually be removed from SDL.
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
......@@ -36,7 +41,6 @@
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_umsaudio.h"
/* The tag name used by UMS audio */
......@@ -152,7 +156,7 @@ Audio_CreateDevice(int devindex)
AudioBootStrap UMS_bootstrap = {
UMS_DRIVER_NAME, "AIX UMS audio",
Audio_Available, Audio_CreateDevice
Audio_Available, Audio_CreateDevice, 0
};
static Uint8 *
......
......@@ -30,7 +30,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
......
......@@ -35,71 +35,13 @@
#include "win_ce_semaphore.h"
#endif
/* Audio driver functions */
static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DIB_ThreadInit(_THIS);
static void DIB_WaitAudio(_THIS);
static Uint8 *DIB_GetAudioBuf(_THIS);
static void DIB_PlayAudio(_THIS);
static void DIB_WaitDone(_THIS);
static void DIB_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
return (1);
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DIB_OpenAudio;
this->ThreadInit = DIB_ThreadInit;
this->WaitAudio = DIB_WaitAudio;
this->PlayAudio = DIB_PlayAudio;
this->GetAudioBuf = DIB_GetAudioBuf;
this->WaitDone = DIB_WaitDone;
this->CloseAudio = DIB_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap WAVEOUT_bootstrap = {
"waveout", "Win95/98/NT/2000 WaveOut",
Audio_Available, Audio_CreateDevice
};
#if defined(_WIN32_WCE)
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
#elif defined(WIN64)
#define WINDOWS_OS_NAME "Win64"
#else
#define WINDOWS_OS_NAME "Win32"
#endif
/* The Win32 callback for filling the WAVE device */
static void CALLBACK
......@@ -114,9 +56,9 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
/* Signal that we are done playing a buffer */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
ReleaseSemaphoreCE(audio_sem, 1, NULL);
ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
#else
ReleaseSemaphore(audio_sem, 1, NULL);
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
#endif
}
......@@ -146,48 +88,47 @@ SetMMerror(char *function, MMRESULT code)
/* Set high priority for the audio thread */
static void
DIB_ThreadInit(_THIS)
WINWAVEOUT_ThreadInit(_THIS)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
void
DIB_WaitAudio(_THIS)
WINWAVEOUT_WaitDevice(_THIS)
{
/* Wait for an audio chunk to finish */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
WaitForSemaphoreCE(audio_sem, INFINITE);
WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
#else
WaitForSingleObject(audio_sem, INFINITE);
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
#endif
}
Uint8 *
DIB_GetAudioBuf(_THIS)
WINWAVEOUT_GetDeviceBuf(_THIS)
{
Uint8 *retval;
retval = (Uint8 *) (wavebuf[next_buffer].lpData);
return retval;
return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData);
}
void
DIB_PlayAudio(_THIS)
WINWAVEOUT_PlayDevice(_THIS)
{
/* Queue it up */
waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
next_buffer = (next_buffer + 1) % NUM_BUFFERS;
waveOutWrite(this->hidden->sound,
&this->hidden->wavebuf[this->hidden->next_buffer],
sizeof (this->hidden->wavebuf[0]));
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
void
DIB_WaitDone(_THIS)
WINWAVEOUT_WaitDone(_THIS)
{
int i, left;
do {
left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) {
if (wavebuf[i].dwFlags & WHDR_DONE) {
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
--left;
}
}
......@@ -199,143 +140,197 @@ DIB_WaitDone(_THIS)
}
void
DIB_CloseAudio(_THIS)
WINWAVEOUT_CloseDevice(_THIS)
{
int i;
/* Close up audio */
if (audio_sem) {
if (this->hidden != NULL) {
int i;
if (this->hidden->audio_sem) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
CloseSynchHandle(audio_sem);
CloseSynchHandle(this->hidden->audio_sem);
#else
CloseHandle(audio_sem);
CloseHandle(this->hidden->audio_sem);
#endif
}
if (sound) {
waveOutClose(sound);
}
this->hidden->audio_sem = 0;
}
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
wavebuf[i].dwUser = 0xFFFF;
if (this->hidden->sound) {
waveOutClose(this->hidden->sound);
this->hidden->sound = 0;
}
}
/* Free raw mixing buffer */
if (mixbuf != NULL) {
SDL_free(mixbuf);
mixbuf = NULL;
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->sound,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwUser = 0xFFFF;
}
}
if (this->hidden->mixbuf != NULL) {
/* Free raw mixing buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
int
DIB_OpenAudio(_THIS, SDL_AudioSpec * spec)
WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
MMRESULT result;
int i;
WAVEFORMATEX waveformat;
int i;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Initialize the wavebuf structures for closing */
sound = NULL;
audio_sem = NULL;
for (i = 0; i < NUM_BUFFERS; ++i)
wavebuf[i].dwUser = 0xFFFF;
mixbuf = NULL;
this->hidden->wavebuf[i].dwUser = 0xFFFF;
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
_this->spec.format = test_format;
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
break; /* valid. */
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) {
WINWAVEOUT_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return 0;
}
/* Set basic WAVE format parameters */
SDL_memset(&waveformat, 0, sizeof(waveformat));
SDL_memset(&waveformat, '\0', sizeof (waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
/* Determine the audio parameters from the AudioSpec */
switch (SDL_AUDIO_BITSIZE(spec->format)) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
waveformat.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
waveformat.wBitsPerSample = 16;
break;
case 32:
/* Signed 32 bit audio data */
spec->format = AUDIO_S32;
waveformat.wBitsPerSample = 32;
break;
default:
SDL_SetError("Unsupported audio format");
return (-1);
}
waveformat.nChannels = spec->channels;
waveformat.nSamplesPerSec = spec->freq;
if (this->spec.channels > 2)
this->spec.channels = 2; /* !!! FIXME: is this right? */
waveformat.nChannels = this->spec.channels;
waveformat.nSamplesPerSec = this->spec.freq;
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
if (spec->samples < (spec->freq / 4))
spec->samples = ((spec->freq / 4) + 3) & ~3;
if (this->spec.samples < (this->spec.freq / 4))
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */
result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutOpen()", result);
return (-1);
return 0;
}
#ifdef SOUND_DEBUG
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps));
result = waveOutGetDevCaps((UINT) this->hidden->sound,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutGetDevCaps()", result);
return (-1);
return 0;
}
printf("Audio device: %s\n", caps.szPname);
}
#endif
/* Create the audio buffer semaphore */
this->hidden->audio_sem =
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
#else
audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
#endif
if (audio_sem == NULL) {
if (this->hidden->audio_sem == NULL) {
WINWAVEOUT_CloseDevice(this);
SDL_SetError("Couldn't create semaphore");
return (-1);
return 0;
}
/* Create the sound buffers */
mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * spec->size);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
if (mixbuf == NULL) {
SDL_SetError("Out of memory");
return (-1);
WINWAVEOUT_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
for (i = 0; i < NUM_BUFFERS; ++i) {
SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size];
wavebuf[i].dwBufferLength = spec->size;
wavebuf[i].dwFlags = WHDR_DONE;
result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
SDL_memset(&this->hidden->wavebuf[i], '\0',
sizeof (this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
(LPSTR) &this->hidden->mixbuf[i * this->spec.size];
result = waveOutPrepareHeader(this->hidden->sound,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutPrepareHeader()", result);
return (-1);
return 0;
}
}
/* Ready to go! */
next_buffer = 0;
return (0);
return 1; /* Ready to go! */
}
static int
WINWAVEOUT_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = WINWAVEOUT_OpenDevice;
impl->ThreadInit = WINWAVEOUT_ThreadInit;
impl->PlayDevice = WINWAVEOUT_PlayDevice;
impl->WaitDevice = WINWAVEOUT_WaitDevice;
impl->WaitDone = WINWAVEOUT_WaitDone;
impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf;
impl->CloseDevice = WINWAVEOUT_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */
return 1;
}
AudioBootStrap WINWAVEOUT_bootstrap = {
"waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,12 +21,12 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_dibaudio_h
#define _SDL_dibaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2 /* -- Don't lower this! */
......@@ -40,12 +40,6 @@ struct SDL_PrivateAudioData
int next_buffer;
};
/* Old variable names */
#define sound (this->hidden->sound)
#define audio_sem (this->hidden->audio_sem)
#define mixbuf (this->hidden->mixbuf)
#define wavebuf (this->hidden->wavebuf)
#define next_buffer (this->hidden->next_buffer)
#endif /* _SDL_dibaudio_h */
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -28,160 +28,65 @@
#include "../SDL_audio_c.h"
#include "SDL_dx5audio.h"
/* Define this if you want to use DirectX 6 DirectSoundNotify interface */
//#define USE_POSITION_NOTIFY
/* DirectX function pointers for audio */
HRESULT(WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
/* Audio driver functions */
static int DX5_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DX5_ThreadInit(_THIS);
static void DX5_WaitAudio_BusyWait(_THIS);
#ifdef USE_POSITION_NOTIFY
static void DX6_WaitAudio_EventWait(_THIS);
/* !!! FIXME: move this somewhere that other drivers can use it... */
#if defined(_WIN32_WCE)
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
#elif defined(WIN64)
#define WINDOWS_OS_NAME "Win64"
#else
#define WINDOWS_OS_NAME "Win32"
#endif
static void DX5_PlayAudio(_THIS);
static Uint8 *DX5_GetAudioBuf(_THIS);
static void DX5_WaitDone(_THIS);
static void DX5_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
HINSTANCE DSoundDLL;
int dsound_ok;
/* Version check DSOUND.DLL (Is DirectX okay?) */
dsound_ok = 0;
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
if (DSoundDLL != NULL) {
/* We just use basic DirectSound, we're okay */
/* Yay! */
/* Unfortunately, the sound drivers on NT have
higher latencies than the audio buffers used
by many SDL applications, so there are gaps
in the audio - it sounds terrible. Punt for now.
*/
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
switch (ver.dwPlatformId) {
case VER_PLATFORM_WIN32_NT:
if (ver.dwMajorVersion > 4) {
/* Win2K */
dsound_ok = 1;
} else {
/* WinNT */
dsound_ok = 0;
}
break;
default:
/* Win95 or Win98 */
dsound_ok = 1;
break;
}
/* Now check for DirectX 5 or better - otherwise
* we will fail later in DX5_OpenAudio without a chance
* to fall back to the DIB driver. */
if (dsound_ok) {
/* DirectSoundCaptureCreate was added in DX5 */
if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate")))
dsound_ok = 0;
}
/* Clean up.. */
FreeLibrary(DSoundDLL);
}
return (dsound_ok);
}
/* Functions for loading the DirectX functions dynamically */
/* DirectX function pointers for audio */
static HINSTANCE DSoundDLL = NULL;
static HRESULT (WINAPI *DSoundCreate)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN) = NULL;
static void
DX5_Unload(void)
DSOUND_Unload(void)
{
if (DSoundDLL != NULL) {
FreeLibrary(DSoundDLL);
DSoundCreate = NULL;
DSoundDLL = NULL;
}
}
static int
DX5_Load(void)
{
int status;
DX5_Unload();
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
if (DSoundDLL != NULL) {
DSoundCreate = (void *) GetProcAddress(DSoundDLL,
TEXT("DirectSoundCreate"));
}
if (DSoundDLL && DSoundCreate) {
status = 0;
} else {
DX5_Unload();
status = -1;
}
return status;
DSoundCreate = NULL;
DSoundDLL = NULL;
}
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
DX5_Unload();
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static int
DSOUND_Load(void)
{
SDL_AudioDevice *this;
int loaded = 0;
/* Load DirectX */
if (DX5_Load() < 0) {
return (NULL);
}
DSOUND_Unload();
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
if (DSoundDLL == NULL) {
SDL_SetError("DirectSound: failed to load DSOUND.DLL");
} else {
/* Now make sure we have DirectX 5 or better... */
/* (DirectSoundCaptureCreate was added in DX5) */
if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) {
SDL_SetError("DirectSound: System doesn't appear to have DX5.");
} else {
DSoundCreate = (void *) GetProcAddress(DSoundDLL,
TEXT("DirectSoundCreate"));
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DX5_OpenAudio;
this->ThreadInit = DX5_ThreadInit;
this->WaitAudio = DX5_WaitAudio_BusyWait;
this->PlayAudio = DX5_PlayAudio;
this->GetAudioBuf = DX5_GetAudioBuf;
this->WaitDone = DX5_WaitDone;
this->CloseAudio = DX5_CloseAudio;
if (!DSoundCreate) {
SDL_SetError("DirectSound: Failed to find DirectSoundCreate");
} else {
loaded = 1;
}
}
this->free = Audio_DeleteDevice;
if (!loaded) {
DSOUND_Unload();
}
return this;
return loaded;
}
AudioBootStrap DSOUND_bootstrap = {
"dsound", "Win95/98/2000 DirectSound",
Audio_Available, Audio_CreateDevice
};
static void
SetDSerror(const char *function, int code)
......@@ -192,8 +97,7 @@ SetDSerror(const char *function, int code)
errbuf[0] = 0;
switch (code) {
case E_NOINTERFACE:
error =
"Unsupported interface\n-- Is DirectX 5.0 or later installed?";
error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
break;
case DSERR_ALLOCATED:
error = "Audio device in use";
......@@ -241,32 +145,36 @@ SetDSerror(const char *function, int code)
/* DirectSound needs to be associated with a window */
static HWND mainwin = NULL;
/* */
void
DX5_SoundFocus(HWND hwnd)
DSOUND_SoundFocus(HWND hwnd)
{
/* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
mainwin = hwnd;
}
static void
DX5_ThreadInit(_THIS)
DSOUND_ThreadInit(_THIS)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
static void
DX5_WaitAudio_BusyWait(_THIS)
DSOUND_WaitDevice(_THIS)
{
DWORD status;
DWORD cursor, junk;
HRESULT result;
DWORD status = 0;
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
/* Semi-busy wait, since we have no way of getting play notification
on a primary mixing buffer located in hardware (DirectX 5.0)
*/
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf);
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCurrentPosition", result);
......@@ -274,21 +182,22 @@ DX5_WaitAudio_BusyWait(_THIS)
return;
}
while ((cursor / mixlen) == lastchunk) {
while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1);
/* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(mixbuf, &status);
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
IDirectSoundBuffer_Restore(mixbuf);
IDirectSoundBuffer_GetStatus(mixbuf, &status);
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
break;
}
}
if (!(status & DSBSTATUS_PLAYING)) {
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
DSBPLAY_LOOPING);
if (result == DS_OK) {
continue;
}
......@@ -299,7 +208,7 @@ DX5_WaitAudio_BusyWait(_THIS)
}
/* Find out where we are playing */
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result);
......@@ -308,222 +217,122 @@ DX5_WaitAudio_BusyWait(_THIS)
}
}
#ifdef USE_POSITION_NOTIFY
static void
DX6_WaitAudio_EventWait(_THIS)
{
DWORD status;
HRESULT result;
/* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
IDirectSoundBuffer_Restore(mixbuf);
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
return;
}
}
if (!(status & DSBSTATUS_PLAYING)) {
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound Play", result);
#endif
return;
}
}
WaitForSingleObject(audio_event, INFINITE);
}
#endif /* USE_POSITION_NOTIFY */
static void
DX5_PlayAudio(_THIS)
DSOUND_PlayDevice(_THIS)
{
/* Unlock the buffer, allowing it to play */
if (locked_buf) {
IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
if (this->hidden->locked_buf) {
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
this->hidden->locked_buf,
this->hidden->mixlen, NULL, 0);
}
}
static Uint8 *
DX5_GetAudioBuf(_THIS)
DSOUND_GetDeviceBuf(_THIS)
{
DWORD cursor, junk;
HRESULT result;
DWORD rawlen;
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
DWORD rawlen = 0;
/* Figure out which blocks to fill next */
locked_buf = NULL;
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
this->hidden->locked_buf = NULL;
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf);
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
}
if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result);
return (NULL);
}
cursor /= mixlen;
cursor /= this->hidden->mixlen;
#ifdef DEBUG_SOUND
/* Detect audio dropouts */
{
DWORD spot = cursor;
if (spot < lastchunk) {
spot += NUM_BUFFERS;
if (spot < this->hidden->lastchunk) {
spot += this->hidden->num_buffers;
}
if (spot > lastchunk + 1) {
if (spot > this->hidden->lastchunk + 1) {
fprintf(stderr, "Audio dropout, missed %d fragments\n",
(spot - (lastchunk + 1)));
(spot - (this->hidden->lastchunk + 1)));
}
}
#endif
lastchunk = cursor;
cursor = (cursor + 1) % NUM_BUFFERS;
cursor *= mixlen;
this->hidden->lastchunk = cursor;
cursor = (cursor + 1) % this->hidden->num_buffers;
cursor *= this->hidden->mixlen;
/* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
(LPVOID *) & locked_buf, &rawlen, NULL,
&junk, 0);
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
(LPVOID *) &this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf);
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
(LPVOID *) & locked_buf, &rawlen,
NULL, &junk, 0);
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
(LPVOID *) &this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
}
if (result != DS_OK) {
SetDSerror("DirectSound Lock", result);
return (NULL);
}
return (locked_buf);
return (this->hidden->locked_buf);
}
static void
DX5_WaitDone(_THIS)
DSOUND_WaitDone(_THIS)
{
Uint8 *stream;
Uint8 *stream = DSOUND_GetDeviceBuf(this);
/* Wait for the playing chunk to finish */
stream = this->GetAudioBuf(this);
if (stream != NULL) {
SDL_memset(stream, silence, mixlen);
this->PlayAudio(this);
SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
DSOUND_PlayDevice(this);
}
this->WaitAudio(this);
DSOUND_WaitDevice(this);
/* Stop the looping sound buffer */
IDirectSoundBuffer_Stop(mixbuf);
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
}
static void
DX5_CloseAudio(_THIS)
DSOUND_CloseDevice(_THIS)
{
if (sound != NULL) {
if (mixbuf != NULL) {
/* Clean up the audio buffer */
IDirectSoundBuffer_Release(mixbuf);
mixbuf = NULL;
}
if (audio_event != NULL) {
CloseHandle(audio_event);
audio_event = NULL;
if (this->hidden != NULL) {
if (this->hidden->sound != NULL) {
if (this->hidden->mixbuf != NULL) {
/* Clean up the audio buffer */
IDirectSoundBuffer_Release(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
IDirectSound_Release(this->hidden->sound);
this->hidden->sound = NULL;
}
IDirectSound_Release(sound);
sound = NULL;
}
}
#ifdef USE_PRIMARY_BUFFER
/* This function tries to create a primary audio buffer, and returns the
number of audio chunks available in the created buffer.
*/
static int
CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
Uint32 chunksize)
{
HRESULT result;
DSBUFFERDESC format;
DSBCAPS caps;
int numchunks;
/* Try to set primary mixing privileges */
result = IDirectSound_SetCooperativeLevel(sndObj, focus,
DSSCL_WRITEPRIMARY);
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetCooperativeLevel", result);
#endif
return (-1);
SDL_free(this->hidden);
this->hidden = NULL;
}
/* Try to create the primary buffer */
SDL_memset(&format, 0, sizeof(format));
format.dwSize = sizeof(format);
format.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2);
format.dwFlags |= DSBCAPS_STICKYFOCUS;
#ifdef USE_POSITION_NOTIFY
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
#endif
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound CreateSoundBuffer", result);
#endif
return (-1);
}
/* Check the size of the fragment buffer */
SDL_memset(&caps, 0, sizeof(caps));
caps.dwSize = sizeof(caps);
result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCaps", result);
#endif
IDirectSoundBuffer_Release(*sndbuf);
return (-1);
}
if ((chunksize > caps.dwBufferBytes) ||
((caps.dwBufferBytes % chunksize) != 0)) {
/* The primary buffer size is not a multiple of 'chunksize'
-- this hopefully doesn't happen when 'chunksize' is a
power of 2.
*/
IDirectSoundBuffer_Release(*sndbuf);
SDL_SetError
("Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
caps.dwBufferBytes, chunksize);
return (-1);
}
numchunks = (caps.dwBufferBytes / chunksize);
/* Set the primary audio format */
result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetFormat", result);
#endif
IDirectSoundBuffer_Release(*sndbuf);
return (-1);
}
return (numchunks);
}
#endif /* USE_PRIMARY_BUFFER */
/* This function tries to create a secondary audio buffer, and returns the
number of audio chunks available in the created buffer.
*/
static int
CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
Uint32 chunksize)
CreateSecondary(_THIS, HWND focus, WAVEFORMATEX *wavefmt)
{
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = this->hidden->mixbuf;
Uint32 chunksize = this->spec.size;
const int numchunks = 8;
HRESULT result;
HRESULT result = DS_OK;
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
......@@ -538,9 +347,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
DSSCL_NORMAL);
}
if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetCooperativeLevel", result);
#endif
return (-1);
}
......@@ -548,9 +355,6 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
SDL_memset(&format, 0, sizeof(format));
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
#ifdef USE_POSITION_NOTIFY
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
#endif
if (!focus) {
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
} else {
......@@ -578,11 +382,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
(LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
DSBLOCK_ENTIREBUFFER);
if (result == DS_OK) {
if (wavefmt->wBitsPerSample == 8) {
SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
} else {
SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
}
SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
IDirectSoundBuffer_Unlock(*sndbuf,
(LPVOID) pvAudioPtr1, dwAudioBytes1,
(LPVOID) pvAudioPtr2, dwAudioBytes2);
......@@ -592,148 +392,125 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
return (numchunks);
}
/* This function tries to set position notify events on the mixing buffer */
#ifdef USE_POSITION_NOTIFY
static int
CreateAudioEvent(_THIS)
DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
{
LPDIRECTSOUNDNOTIFY notify;
DSBPOSITIONNOTIFY *notify_positions;
int i, retval;
HRESULT result;
WAVEFORMATEX waveformat;
int valid_format = 0;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
/* Default to fail on exit */
retval = -1;
notify = NULL;
/* !!! FIXME: handle devname */
/* !!! FIXME: handle iscapture */
/* Query for the interface */
result = IDirectSoundBuffer_QueryInterface(mixbuf,
&IID_IDirectSoundNotify,
(void *) &notify);
if (result != DS_OK) {
goto done;
}
/* Allocate the notify structures */
notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc(NUM_BUFFERS *
sizeof
(*notify_positions));
if (notify_positions == NULL) {
goto done;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Create the notify event */
audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (audio_event == NULL) {
goto done;
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
this->spec.format = test_format;
valid_format = 1;
break;
}
test_format = SDL_NextAudioFormat();
}
/* Set up the notify structures */
for (i = 0; i < NUM_BUFFERS; ++i) {
notify_positions[i].dwOffset = i * mixlen;
notify_positions[i].hEventNotify = audio_event;
}
result = IDirectSoundNotify_SetNotificationPositions(notify,
NUM_BUFFERS,
notify_positions);
if (result == DS_OK) {
retval = 0;
}
done:
if (notify != NULL) {
IDirectSoundNotify_Release(notify);
if (!valid_format) {
DSOUND_CloseDevice(this);
SDL_SetError("DirectSound: Unsupported audio format");
return 0;
}
return (retval);
}
#endif /* USE_POSITION_NOTIFY */
static int
DX5_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
HRESULT result;
WAVEFORMATEX waveformat;
/* Set basic WAVE format parameters */
SDL_memset(&waveformat, 0, sizeof(waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
/* Determine the audio parameters from the AudioSpec */
switch (SDL_AUDIO_BITSIZE(spec->format)) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
silence = 0x80;
waveformat.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
silence = 0x00;
waveformat.wBitsPerSample = 16;
break;
case 32:
/* Signed 32 bit audio data */
spec->format = AUDIO_S32;
silence = 0x00;
waveformat.wBitsPerSample = 32;
break;
default:
SDL_SetError("Unsupported audio format");
return (-1);
}
waveformat.nChannels = spec->channels;
waveformat.nSamplesPerSec = spec->freq;
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
waveformat.nChannels = this->spec.channels;
waveformat.nSamplesPerSec = this->spec.freq;
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */
result = DSoundCreate(NULL, &sound, NULL);
result = DSoundCreate(NULL, &this->hidden->sound, NULL);
if (result != DS_OK) {
DSOUND_CloseDevice(this);
SetDSerror("DirectSoundCreate", result);
return (-1);
return 0;
}
/* Create the audio buffer to which we write */
NUM_BUFFERS = -1;
#ifdef USE_PRIMARY_BUFFER
if (mainwin) {
NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
&waveformat, spec->size);
this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
if (this->hidden->num_buffers < 0) {
DSOUND_CloseDevice(this);
return 0;
}
#endif /* USE_PRIMARY_BUFFER */
if (NUM_BUFFERS < 0) {
NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
&waveformat, spec->size);
if (NUM_BUFFERS < 0) {
return (-1);
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
this->hidden->mixlen = this->spec.size;
return 1; /* good to go. */
}
static void
DSOUND_Deinitialize(void)
{
DSOUND_Unload();
}
static int
DSOUND_Init(SDL_AudioDriverImpl *impl)
{
OSVERSIONINFO ver;
/*
* Unfortunately, the sound drivers on NT have higher latencies than the
* audio buffers used by many SDL applications, so there are gaps in the
* audio - it sounds terrible. Punt for now.
*/
SDL_memset(&ver, '\0', sizeof (OSVERSIONINFO));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
if (ver.dwMajorVersion <= 4) {
return 0; /* NT4.0 or earlier. Disable dsound support. */
}
#ifdef DEBUG_SOUND
fprintf(stderr, "Using secondary audio buffer\n");
#endif
}
#ifdef DEBUG_SOUND
else
fprintf(stderr, "Using primary audio buffer\n");
#endif
/* The buffer will auto-start playing in DX5_WaitAudio() */
lastchunk = 0;
mixlen = spec->size;
#ifdef USE_POSITION_NOTIFY
/* See if we can use DirectX 6 event notification */
if (CreateAudioEvent(this) == 0) {
this->WaitAudio = DX6_WaitAudio_EventWait;
} else {
this->WaitAudio = DX5_WaitAudio_BusyWait;
if (!DSOUND_Load()) {
return 0;
}
#endif
return (0);
/* Set the function pointers */
impl->OpenDevice = DSOUND_OpenDevice;
impl->PlayDevice = DSOUND_PlayDevice;
impl->WaitDevice = DSOUND_WaitDevice;
impl->WaitDone = DSOUND_WaitDone;
impl->ThreadInit = DSOUND_ThreadInit;
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
impl->CloseDevice = DSOUND_CloseDevice;
impl->Deinitialize = DSOUND_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME */
return 1;
}
AudioBootStrap DSOUND_bootstrap = {
"dsound", WINDOWS_OS_NAME "DirectSound", DSOUND_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */
......@@ -21,14 +21,14 @@
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#ifndef _SDL_dx5audio_h
#define _SDL_dx5audio_h
#include "directx.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
/* The DirectSound objects */
......@@ -36,23 +36,12 @@ struct SDL_PrivateAudioData
{
LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf;
int NUM_BUFFERS;
int mixlen, silence;
int num_buffers;
int mixlen;
DWORD lastchunk;
Uint8 *locked_buf;
HANDLE audio_event;
};
/* Old variable names */
#define sound (this->hidden->sound)
#define mixbuf (this->hidden->mixbuf)
#define NUM_BUFFERS (this->hidden->NUM_BUFFERS)
#define mixlen (this->hidden->mixlen)
#define silence (this->hidden->silence)
#define lastchunk (this->hidden->lastchunk)
#define locked_buf (this->hidden->locked_buf)
#define audio_event (this->hidden->audio_event)
#endif /* _SDL_lowaudio_h */
#endif /* _SDL_dx5audio_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -165,7 +165,7 @@ SDL_GetMouseFocusWindow()
return mouse->focus;
}
static int
static int SDLCALL
FlushMouseMotion(void *param, SDL_Event * event)
{
if (event->type == SDL_MOUSEMOTION
......
......@@ -65,24 +65,28 @@ SDL_GetTicks(void)
*/
/* inline asm to avoid runtime inclusion */
_asm {
push edx
push eax
mov eax, dword ptr hires_now
mov edx, dword ptr hires_now + 4
sub eax, dword ptr hires_start_ticks
sbb edx, dword ptr hires_start_ticks + 4
mov ebx, 1000
mov ecx, edx
mul ebx
push eax
push edx
mov eax, ecx
mul ebx
pop eax
add edx, eax
pop eax
mov ebx, dword ptr hires_ticks_per_second
div ebx mov dword ptr ticks, eax pop edx pop eax}
push edx
push eax
mov eax, dword ptr hires_now
mov edx, dword ptr hires_now + 4
sub eax, dword ptr hires_start_ticks
sbb edx, dword ptr hires_start_ticks + 4
mov ebx, 1000
mov ecx, edx
mul ebx
push eax
push edx
mov eax, ecx
mul ebx
pop eax
add edx, eax
pop eax
mov ebx, dword ptr hires_ticks_per_second
div ebx
mov dword ptr ticks, eax
pop edx
pop eax
}
return ticks;
......@@ -178,7 +182,7 @@ SDL_Delay(Uint32 ms)
static int timer_alive = 0;
static SDL_Thread *timer = NULL;
static int
static int SDLCALL
RunTimer(void *unused)
{
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
......
......@@ -33,10 +33,10 @@
#define SDL_RENDERCOPY_NEAREST 0x0100
typedef struct {
void *src;
Uint8 *src;
int src_w, src_h;
int src_pitch;
void *dst;
Uint8 *dst;
int dst_w, dst_h;
int dst_pitch;
void *aux_data;
......@@ -44,7 +44,7 @@ typedef struct {
Uint8 r, g, b, a;
} SDL_RenderCopyData;
typedef int (*SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
typedef int (SDLCALL * SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
extern SDL_RenderCopyFunc SDLCALL SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode);
......
......@@ -7,7 +7,7 @@ EXE = @EXE@
CFLAGS = @CFLAGS@
LIBS = @LIBS@
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE)
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE)
all: Makefile $(TARGETS)
......@@ -23,6 +23,12 @@ graywin$(EXE): $(srcdir)/graywin.c
loopwave$(EXE): $(srcdir)/loopwave.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
testaudioinfo$(EXE): $(srcdir)/testaudioinfo.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
testalpha$(EXE): $(srcdir)/testalpha.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@
......
......@@ -69,26 +69,12 @@ main(int argc, char *argv[])
{
int i, n;
/* Print available audio drivers */
n = SDL_GetNumAudioDrivers();
if (n == 0) {
printf("No built-in audio drivers\n");
} else {
printf("Built-in audio drivers:");
for (i = 0; i < n; ++i) {
if (i > 0) {
printf(",");
}
printf(" %s", SDL_GetAudioDriver(i));
}
printf("\n");
}
/* Load the SDL library */
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1);
}
if (argv[1] == NULL) {
argv[1] = "sample.wav";
}
......@@ -120,7 +106,6 @@ main(int argc, char *argv[])
SDL_PauseAudio(0);
/* Let the audio run */
printf("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING))
SDL_Delay(1000);
......
#include "SDL.h"
static void print_devices(int iscapture)
{
const char *typestr = ((iscapture) ? "capture" : "output");
int n = SDL_GetNumAudioDevices(iscapture);
printf("%s devices:\n", typestr);
if (n == -1)
printf(" Driver can't detect specific devices.\n\n", typestr);
else if (n == 0)
printf(" No %s devices found.\n\n", typestr);
else
{
int i;
for (i = 0; i < n; i++) {
printf(" %s\n", SDL_GetAudioDeviceName(i, iscapture));
}
printf("\n");
}
}
int main(int argc, char **argv)
{
/* Print available audio drivers */
int n = SDL_GetNumAudioDrivers();
if (n == 0) {
printf("No built-in audio drivers\n\n");
} else {
int i;
printf("Built-in audio drivers:\n");
for (i = 0; i < n; ++i) {
printf(" %s\n", SDL_GetAudioDriver(i));
}
printf("\n");
}
/* Load the SDL library */
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1);
}
printf("Using audio driver: %s\n\n", SDL_GetCurrentAudioDriver());
print_devices(0);
print_devices(1);
SDL_Quit();
return 0;
}
#include "SDL.h"
static SDL_AudioSpec spec;
static Uint8 *sound = NULL; /* Pointer to wave data */
static Uint32 soundlen = 0; /* Length of wave data */
typedef struct
{
SDL_AudioDeviceID dev;
int soundpos;
volatile int done;
} callback_data;
void SDLCALL play_through_once(void *arg, Uint8 * stream, int len)
{
callback_data *cbd = (callback_data *) arg;
Uint8 *waveptr = sound + cbd->soundpos;
int waveleft = soundlen - cbd->soundpos;
int cpy = len;
if (cpy > waveleft)
cpy = waveleft;
memcpy(stream, waveptr, cpy);
len -= cpy;
cbd->soundpos += cpy;
if (len > 0) {
stream += cpy;
memset(stream, spec.silence, len);
cbd->done++;
}
}
static void test_multi_audio(int devcount)
{
callback_data cbd[64];
int keep_going = 1;
int i;
if (devcount > 64) {
fprintf(stderr, "Too many devices (%d), clamping to 64...\n", devcount);
devcount = 64;
}
spec.callback = play_through_once;
for (i = 0; i < devcount; i++) {
const char *devname = SDL_GetAudioDeviceName(i, 0);
printf("playing on device #%d: ('%s')...", i, devname);
fflush(stdout);
memset(&cbd[0], '\0', sizeof (callback_data));
spec.userdata = &cbd[0];
cbd[0].dev = SDL_OpenAudioDevice(devname, 0, &spec, NULL);
if (cbd[0].dev == 0) {
printf("Open device failed: %s\n", SDL_GetError());
} else {
SDL_PauseAudioDevice(cbd[0].dev, 0);
while (!cbd[0].done)
SDL_Delay(100);
SDL_PauseAudioDevice(cbd[0].dev, 1);
printf("done.\n");
SDL_CloseAudioDevice(cbd[0].dev);
}
}
memset(cbd, '\0', sizeof (cbd));
printf("playing on all devices...\n");
for (i = 0; i < devcount; i++) {
const char *devname = SDL_GetAudioDeviceName(i, 0);
spec.userdata = &cbd[i];
cbd[i].dev = SDL_OpenAudioDevice(devname, 0, &spec, NULL);
if (cbd[i].dev == 0) {
printf("Open device %d failed: %s\n", i, SDL_GetError());
}
}
for (i = 0; i < devcount; i++) {
if (cbd[i].dev) {
SDL_PauseAudioDevice(cbd[i].dev, 0);
}
}
while (keep_going) {
keep_going = 0;
for (i = 0; i < devcount; i++) {
if ((cbd[i].dev) && (!cbd[i].done)) {
keep_going = 1;
}
}
SDL_Delay(100);
}
for (i = 0; i < devcount; i++) {
if (cbd[i].dev) {
SDL_PauseAudioDevice(cbd[i].dev, 1);
SDL_CloseAudioDevice(cbd[i].dev);
}
}
printf("All done!\n");
}
int main(int argc, char **argv)
{
int devcount = 0;
/* Load the SDL library */
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1);
}
printf("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
devcount = SDL_GetNumAudioDevices(0);
if (devcount < 1) {
fprintf(stderr, "Don't see any specific audio devices!\n");
} else {
if (argv[1] == NULL) {
argv[1] = "sample.wav";
}
/* Load the wave file into memory */
if (SDL_LoadWAV(argv[1], &spec, &sound, &soundlen) == NULL) {
fprintf(stderr, "Couldn't load %s: %s\n", argv[1], SDL_GetError());
} else {
test_multi_audio(devcount);
SDL_FreeWAV(sound);
}
}
SDL_Quit();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment