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() ...@@ -511,9 +511,17 @@ CheckNAS()
AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]), AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
, enable_nas=yes) , enable_nas=yes)
if test x$enable_audio = xyes -a x$enable_nas = xyes; then 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) AC_MSG_CHECKING(for NAS audio support)
have_nas=no 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 have_nas=yes
NAS_CFLAGS="-I/usr/X11R6/include/" NAS_CFLAGS="-I/usr/X11R6/include/"
NAS_LIBS="-L/usr/X11R6/lib -laudio -lXt" NAS_LIBS="-L/usr/X11R6/lib -laudio -lXt"
...@@ -525,12 +533,40 @@ AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]), ...@@ -525,12 +533,40 @@ AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
have_nas=yes have_nas=yes
NAS_LIBS="-lnas -lXt" NAS_LIBS="-lnas -lXt"
fi fi
AC_MSG_RESULT($have_nas) AC_MSG_RESULT($have_nas)
if test x$have_nas = xyes; then 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) AC_DEFINE(SDL_AUDIO_DRIVER_NAS)
SOURCES="$SOURCES $srcdir/src/audio/nas/*.c" SOURCES="$SOURCES $srcdir/src/audio/nas/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS" EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
have_audio=yes have_audio=yes
fi fi
fi fi
...@@ -2006,7 +2042,7 @@ case "$host" in ...@@ -2006,7 +2042,7 @@ case "$host" in
have_audio=yes have_audio=yes
;; ;;
aix) aix)
AC_DEFINE(SDL_AUDIO_DRIVER_PAUD) AC_DEFINE(SDL_AUDIO_DRIVER_PAUDIO)
SOURCES="$SOURCES $srcdir/src/audio/paudio/*.c" SOURCES="$SOURCES $srcdir/src/audio/paudio/*.c"
have_audio=yes have_audio=yes
;; ;;
...@@ -2206,7 +2242,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau ...@@ -2206,7 +2242,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
CheckBeGL CheckBeGL
# Set up files for the audio library # Set up files for the audio library
if test x$enable_audio = xyes; then 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" SOURCES="$SOURCES $srcdir/src/audio/baudio/*.cc"
have_audio=yes have_audio=yes
fi fi
...@@ -2323,7 +2359,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau ...@@ -2323,7 +2359,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
# If either the audio or CD driver is used, add the AudioUnit framework # 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 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 fi
;; ;;
*-*-mint*) *-*-mint*)
......
...@@ -153,7 +153,7 @@ typedef struct SDL_AudioCVT ...@@ -153,7 +153,7 @@ typedef struct SDL_AudioCVT
/* Function prototypes */ /* 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. * order that they are normally initialized by default.
*/ */
extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void); extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
...@@ -212,7 +212,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(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 * may modify the requested size of the audio buffer, you should allocate
* any local mixing buffers after you open the audio device. * 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); SDL_AudioSpec * obtained);
/* /*
...@@ -228,6 +228,13 @@ typedef Uint32 SDL_AudioDeviceID; ...@@ -228,6 +228,13 @@ typedef Uint32 SDL_AudioDeviceID;
/* /*
* Get the number of available devices exposed by the current driver. * Get the number of available devices exposed by the current driver.
* Only valid after a successfully initializing the audio subsystem. * 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); extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
...@@ -235,15 +242,28 @@ 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. * Get the human-readable name of a specific audio device.
* Must be a value between 0 and (number of audio devices-1). * Must be a value between 0 and (number of audio devices-1).
* Only valid after a successfully initializing the audio subsystem. * 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, extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
int iscapture); int iscapture);
/* /*
* Open a specific audio device. Passing in a device name of NULL is * Open a specific audio device. Passing in a device name of NULL requests
* equivalent to SDL_OpenAudio(). Returns 0 on error, a valid device ID * the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
* on success. * 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 extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
*device, *device,
......
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC #undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#undef SDL_AUDIO_DRIVER_ARTS #undef SDL_AUDIO_DRIVER_ARTS
#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC #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_BSD
#undef SDL_AUDIO_DRIVER_COREAUDIO #undef SDL_AUDIO_DRIVER_COREAUDIO
#undef SDL_AUDIO_DRIVER_DART #undef SDL_AUDIO_DRIVER_DART
...@@ -168,9 +168,10 @@ ...@@ -168,9 +168,10 @@
#undef SDL_AUDIO_DRIVER_MINT #undef SDL_AUDIO_DRIVER_MINT
#undef SDL_AUDIO_DRIVER_MMEAUDIO #undef SDL_AUDIO_DRIVER_MMEAUDIO
#undef SDL_AUDIO_DRIVER_NAS #undef SDL_AUDIO_DRIVER_NAS
#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
#undef SDL_AUDIO_DRIVER_OSS #undef SDL_AUDIO_DRIVER_OSS
#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H #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_QNXNTO
#undef SDL_AUDIO_DRIVER_SNDMGR #undef SDL_AUDIO_DRIVER_SNDMGR
#undef SDL_AUDIO_DRIVER_SUNAUDIO #undef SDL_AUDIO_DRIVER_SUNAUDIO
......
...@@ -91,7 +91,7 @@ typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned, ...@@ -91,7 +91,7 @@ typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code); typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
#endif #endif
extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (*fn) (void *), extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (SDLCALL * f) (void *),
void *data, void *data,
pfnSDL_CurrentBeginThread pfnSDL_CurrentBeginThread
pfnBeginThread, pfnBeginThread,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
/* Routine to get the thread-specific error variable */ /* Routine to get the thread-specific error variable */
#if SDL_THREADS_DISABLED #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 */ /* The SDL_arraysize(The ),default (non-thread-safe) global error variable */
static SDL_error SDL_global_error; static SDL_error SDL_global_error;
#define SDL_GetErrBuf() (&SDL_global_error) #define SDL_GetErrBuf() (&SDL_global_error)
......
...@@ -28,11 +28,48 @@ ...@@ -28,11 +28,48 @@
#include "SDL_audiomem.h" #include "SDL_audiomem.h"
#include "SDL_sysaudio.h" #include "SDL_sysaudio.h"
#ifdef __OS2__ #define _THIS SDL_AudioDevice *this
/* We'll need the DosSetPriority() API! */
#define INCL_DOSPROCESS static SDL_AudioDriver current_audio;
#include <os2.h> static SDL_AudioDevice *open_devices[16];
#endif
/* !!! 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 */ /* Available audio drivers */
static AudioBootStrap *bootstrap[] = { static AudioBootStrap *bootstrap[] = {
...@@ -70,11 +107,11 @@ static AudioBootStrap *bootstrap[] = { ...@@ -70,11 +107,11 @@ static AudioBootStrap *bootstrap[] = {
#if SDL_AUDIO_DRIVER_WAVEOUT #if SDL_AUDIO_DRIVER_WAVEOUT
&WAVEOUT_bootstrap, &WAVEOUT_bootstrap,
#endif #endif
#if SDL_AUDIO_DRIVER_PAUD #if SDL_AUDIO_DRIVER_PAUDIO
&Paud_bootstrap, &PAUDIO_bootstrap,
#endif #endif
#if SDL_AUDIO_DRIVER_BAUDIO #if SDL_AUDIO_DRIVER_BEOSAUDIO
&BAUDIO_bootstrap, &BEOSAUDIO_bootstrap,
#endif #endif
#if SDL_AUDIO_DRIVER_COREAUDIO #if SDL_AUDIO_DRIVER_COREAUDIO
&COREAUDIO_bootstrap, &COREAUDIO_bootstrap,
...@@ -82,9 +119,6 @@ static AudioBootStrap *bootstrap[] = { ...@@ -82,9 +119,6 @@ static AudioBootStrap *bootstrap[] = {
#if SDL_AUDIO_DRIVER_SNDMGR #if SDL_AUDIO_DRIVER_SNDMGR
&SNDMGR_bootstrap, &SNDMGR_bootstrap,
#endif #endif
#if SDL_AUDIO_DRIVER_AHI
&AHI_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_MINT #if SDL_AUDIO_DRIVER_MINT
&MINTAUDIO_GSXB_bootstrap, &MINTAUDIO_GSXB_bootstrap,
&MINTAUDIO_MCSN_bootstrap, &MINTAUDIO_MCSN_bootstrap,
...@@ -109,227 +143,201 @@ static AudioBootStrap *bootstrap[] = { ...@@ -109,227 +143,201 @@ static AudioBootStrap *bootstrap[] = {
#endif #endif
NULL NULL
}; };
SDL_AudioDevice *current_audio = NULL;
/* Various local functions */ static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
int SDL_AudioInit(const char *driver_name); {
void SDL_AudioQuit(void); 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 */ /* The general mixing thread function */
int SDLCALL 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; Uint8 *stream;
int stream_len; int stream_len;
void *udata; void *udata;
void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
int silence; 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 */ /* Perform any thread setup */
if (audio->ThreadInit) { device->threadid = SDL_ThreadID();
audio->ThreadInit(audio); current_audio.impl.ThreadInit(device);
}
audio->threadid = SDL_ThreadID();
/* Set up the mixing function */ /* Set up the mixing function */
fill = audio->spec.callback; fill = device->spec.callback;
udata = audio->spec.userdata; udata = device->spec.userdata;
#if SDL_AUDIO_DRIVER_AHI
audio_configured = 1;
D(bug("Audio configured... Checking for conversion\n")); if (device->convert.needed) {
SDL_mutexP(audio->mixer_lock); if (device->convert.src_format == AUDIO_U8) {
D(bug("Semaphore obtained...\n"));
#endif
if (audio->convert.needed) {
if (audio->convert.src_format == AUDIO_U8) {
silence = 0x80; silence = 0x80;
} else { } else {
silence = 0; silence = 0;
} }
stream_len = audio->convert.len; stream_len = device->convert.len;
} else { } else {
silence = audio->spec.silence; silence = device->spec.silence;
stream_len = audio->spec.size; 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 */ /* Loop, filling the audio buffers */
while (audio->enabled) { while (device->enabled) {
/* Fill the current buffer with sound */ /* Fill the current buffer with sound */
if (audio->convert.needed) { if (device->convert.needed) {
if (audio->convert.buf) { if (device->convert.buf) {
stream = audio->convert.buf; stream = device->convert.buf;
} else { } else {
continue; continue;
} }
} else { } else {
stream = audio->GetAudioBuf(audio); stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) { if (stream == NULL) {
stream = audio->fake_stream; stream = device->fake_stream;
} }
} }
SDL_memset(stream, silence, stream_len);
if (!audio->paused) { /* New code should fill buffer or set it to silence themselves. */
SDL_mutexP(audio->mixer_lock); if (legacy_device) {
SDL_memset(stream, silence, stream_len);
}
if (!device->paused) {
SDL_mutexP(device->mixer_lock);
(*fill) (udata, stream, stream_len); (*fill) (udata, stream, stream_len);
SDL_mutexV(audio->mixer_lock); SDL_mutexV(device->mixer_lock);
} }
/* Convert the audio if necessary */ /* Convert the audio if necessary */
if (audio->convert.needed) { if (device->convert.needed) {
SDL_ConvertAudio(&audio->convert); SDL_ConvertAudio(&device->convert);
stream = audio->GetAudioBuf(audio); stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) { 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 */ /* Ready current buffer for play and change current buffer */
if (stream != audio->fake_stream) { if (stream != device->fake_stream) {
audio->PlayAudio(audio); current_audio.impl.PlayDevice(device);
} }
/* Wait for an audio buffer to become available */ /* Wait for an audio buffer to become available */
if (stream == audio->fake_stream) { if (stream == device->fake_stream) {
SDL_Delay((audio->spec.samples * 1000) / audio->spec.freq); SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
} else { } else {
audio->WaitAudio(audio); current_audio.impl.WaitDevice(device);
} }
} }
/* Wait for the audio to drain.. */ /* Wait for the audio to drain.. */
if (audio->WaitDone) { current_audio.impl.WaitDone(device);
audio->WaitDone(audio);
}
#if SDL_AUDIO_DRIVER_AHI
D(bug("WaitAudio...Done\n"));
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); 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 static SDL_AudioFormat
SDL_ParseAudioFormat(const char *string) SDL_ParseAudioFormat(const char *string)
{ {
SDL_AudioFormat format = 0; #define CHECK_FMT_STRING(x) if (strcmp(string, #x) == 0) return AUDIO_##x
CHECK_FMT_STRING(U8);
switch (*string) { CHECK_FMT_STRING(S8);
case 'U': CHECK_FMT_STRING(U16LSB);
++string; CHECK_FMT_STRING(S16LSB);
format |= 0x0000; CHECK_FMT_STRING(U16MSB);
break; CHECK_FMT_STRING(S16MSB);
case 'S': CHECK_FMT_STRING(U16SYS);
++string; CHECK_FMT_STRING(S16SYS);
format |= 0x8000; CHECK_FMT_STRING(U16);
break; CHECK_FMT_STRING(S16);
default: CHECK_FMT_STRING(S32LSB);
return 0; CHECK_FMT_STRING(S32MSB);
} CHECK_FMT_STRING(S32SYS);
switch (SDL_atoi(string)) { CHECK_FMT_STRING(S32);
case 8: CHECK_FMT_STRING(F32LSB);
string += 1; CHECK_FMT_STRING(F32MSB);
format |= 8; CHECK_FMT_STRING(F32SYS);
break; CHECK_FMT_STRING(F32);
case 16: #undef CHECK_FMT_STRING
string += 2; return 0;
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;
} }
int int
...@@ -350,92 +358,53 @@ SDL_GetAudioDriver(int index) ...@@ -350,92 +358,53 @@ SDL_GetAudioDriver(int index)
int int
SDL_AudioInit(const char *driver_name) SDL_AudioInit(const char *driver_name)
{ {
SDL_AudioDevice *audio; int i = 0;
int i = 0, idx; int initialized = 0;
int tried_to_init = 0;
/* Check to make sure we don't overwrite 'current_audio' */ if (SDL_WasInit(SDL_INIT_AUDIO)) {
if (current_audio != NULL) { SDL_AudioQuit(); /* shutdown driver if already running. */
SDL_AudioQuit();
} }
SDL_memset(&current_audio, '\0', sizeof (current_audio));
SDL_memset(open_devices, '\0', sizeof (open_devices));
/* Select the proper audio driver */ /* Select the proper audio driver */
audio = NULL;
idx = 0;
if (driver_name == NULL) { if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_AUDIODRIVER"); driver_name = SDL_getenv("SDL_AUDIODRIVER");
} }
#if SDL_AUDIO_DRIVER_ESD
if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) { for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
/* Ahem, we know that if ESPEAKER is set, user probably wants /* make sure we should even try this driver before doing so... */
to use ESD, but don't start it if it's not already running. const AudioBootStrap *backend = bootstrap[i];
This probably isn't the place to do this, but... Shh! :) if ( ((driver_name) && (SDL_strcasecmp(backend->name, driver_name))) ||
*/ ((!driver_name) && (backend->demand_only)) ) {
for (i = 0; bootstrap[i]; ++i) { continue;
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
}
} }
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 (!initialized) {
if (driver_name != NULL) { /* specific drivers will set the error message if they fail... */
for (i = 0; bootstrap[i]; ++i) { if (!tried_to_init) {
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 (driver_name) { if (driver_name) {
SDL_SetError("%s not available", driver_name); SDL_SetError("%s not available", driver_name);
} else { } else {
SDL_SetError("No available audio device"); 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); return (0);
} }
...@@ -445,222 +414,369 @@ SDL_AudioInit(const char *driver_name) ...@@ -445,222 +414,369 @@ SDL_AudioInit(const char *driver_name)
const char * const char *
SDL_GetCurrentAudioDriver() SDL_GetCurrentAudioDriver()
{ {
if (current_audio) { return current_audio.name;
return current_audio->name;
}
return (NULL);
} }
int int
SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) SDL_GetNumAudioDevices(int iscapture)
{ {
SDL_AudioDevice *audio; if (!SDL_WasInit(SDL_INIT_AUDIO)) {
const char *env; return -1;
}
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
return 0;
}
/* Start up the audio driver, if necessary */ if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
if (!current_audio) { return 1;
if ((SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
(current_audio == NULL)) {
return (-1);
}
} }
audio = current_audio;
if (audio->opened) { if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
SDL_SetError("Audio device is already opened"); return 1;
return (-1);
} }
/* Verify some parameters */ return current_audio.impl.DetectDevices(iscapture);
if (desired->freq == 0) { }
env = SDL_getenv("SDL_AUDIO_FREQUENCY");
if (env) {
desired->freq = SDL_atoi(env); 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 */ if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
desired->freq = 22050; SDL_SetError("No capture support");
return NULL;
} }
if (desired->format == 0) {
env = SDL_getenv("SDL_AUDIO_FORMAT"); if (index < 0) {
if (env) { SDL_SetError("No such device");
desired->format = SDL_ParseAudioFormat(env); 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) { if (device->fake_stream != NULL) {
/* Pick some default audio format */ SDL_FreeAudioMem(device->fake_stream);
desired->format = AUDIO_S16;
} }
if (desired->channels == 0) { if (device->convert.needed) {
env = SDL_getenv("SDL_AUDIO_CHANNELS"); SDL_FreeAudioMem(device->convert.buf);
if (env) { }
desired->channels = (Uint8) SDL_atoi(env); 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 */ if (orig->format == 0) {
desired->channels = 2; 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 1: /* Mono */
case 2: /* Stereo */ case 2: /* Stereo */
case 4: /* surround */ case 4: /* surround */
case 6: /* surround with center and lfe */ case 6: /* surround with center and lfe */
break; break;
default: default:
SDL_SetError("1 (mono) and 2 (stereo) channels supported"); SDL_SetError("Unsupported number of audio channels.");
return (-1); return 0;
}
if (desired->samples == 0) {
env = SDL_getenv("SDL_AUDIO_SAMPLES");
if (env) {
desired->samples = (Uint16) SDL_atoi(env);
}
} }
if (desired->samples == 0) {
/* Pick a default of ~46 ms at desired frequency */ if (orig->samples == 0) {
int samples = (desired->freq / 1000) * 46; const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
int power2 = 1; if ( (!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0) ) {
while (power2 < samples) { /* Pick a default of ~46 ms at desired frequency */
power2 *= 2; /* !!! 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"); /* Calculate the silence and size of the audio specification */
return (-1); 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 */ if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
#else SDL_SetError("No capture support");
/* Create a semaphore for locking the sound buffers */ return 0;
audio->mixer_lock = SDL_CreateMutex();
if (audio->mixer_lock == NULL) {
SDL_SetError("Couldn't create mixer lock");
SDL_CloseAudio();
return (-1);
} }
#endif /* __MINT__ */
/* Calculate the silence and size of the audio specification */ if (!prepare_audiospec(_desired, &desired)) {
SDL_CalculateAudioSpec(desired); return 0;
}
/* Open the audio subsystem */ /* If app doesn't care about a specific device, let the user override. */
SDL_memcpy(&audio->spec, desired, sizeof(audio->spec)); if (devname == NULL) {
audio->convert.needed = 0; devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
audio->enabled = 1; }
audio->paused = 1;
#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 */ if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
audio->opened = audio->OpenAudio(audio, &audio->spec) + 1; if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
SDL_SetError("No such device");
return 0;
}
devname = NULL;
if (!audio->opened) { for (i = 0; i < SDL_arraysize(open_devices); i++) {
SDL_CloseAudio(); if ((open_devices[i]) && (open_devices[i]->iscapture)) {
return (-1); 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); for (i = 0; i < SDL_arraysize(open_devices); i++) {
D(bug("Created thread...\n")); if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
SDL_SetError("Audio device already open");
return 0;
}
}
}
if (audio->thread == NULL) { device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof (SDL_AudioDevice));
SDL_mutexV(audio->mixer_lock); if (device == NULL) {
SDL_CloseAudio(); SDL_OutOfMemory();
SDL_SetError("Couldn't create audio thread"); return 0;
return (-1);
} }
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) /* Create a semaphore for locking the sound buffers */
SDL_Delay(100); if (!current_audio.impl.SkipMixerLock) {
#endif 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 the audio driver changes the buffer size, accept it */
if (audio->spec.samples != desired->samples) { if (device->spec.samples != desired.samples) {
desired->samples = audio->spec.samples; desired.samples = device->spec.samples;
SDL_CalculateAudioSpec(desired); SDL_CalculateAudioSpec(&device->spec);
} }
/* Allocate a fake audio memory buffer */ /* Allocate a fake audio memory buffer */
audio->fake_stream = SDL_AllocAudioMem(audio->spec.size); device->fake_stream = SDL_AllocAudioMem(device->spec.size);
if (audio->fake_stream == NULL) { if (device->fake_stream == NULL) {
SDL_CloseAudio(); close_audio_device(device);
SDL_OutOfMemory(); SDL_OutOfMemory();
return (-1); return 0;
} }
/* See if we need to do any conversion */ /* See if we need to do any conversion */
if (obtained != NULL) { if (obtained != NULL) {
SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec)); SDL_memcpy(obtained, &device->spec, sizeof(SDL_AudioSpec));
} else if (desired->freq != audio->spec.freq || } else if (desired.freq != device->spec.freq ||
desired->format != audio->spec.format || desired.format != device->spec.format ||
desired->channels != audio->spec.channels) { desired.channels != device->spec.channels) {
/* Build an audio conversion block */ /* Build an audio conversion block */
if (SDL_BuildAudioCVT(&audio->convert, if (SDL_BuildAudioCVT(&device->convert,
desired->format, desired->channels, desired.format, desired.channels,
desired->freq, desired.freq,
audio->spec.format, audio->spec.channels, device->spec.format, device->spec.channels,
audio->spec.freq) < 0) { device->spec.freq) < 0) {
SDL_CloseAudio(); close_audio_device(device);
return (-1); return 0;
} }
if (audio->convert.needed) { if (device->convert.needed) {
audio->convert.len = desired->size; device->convert.len = desired.size;
audio->convert.buf = device->convert.buf =
(Uint8 *) SDL_AllocAudioMem(audio->convert.len * (Uint8 *) SDL_AllocAudioMem(device->convert.len *
audio->convert.len_mult); device->convert.len_mult);
if (audio->convert.buf == NULL) { if (device->convert.buf == NULL) {
SDL_CloseAudio(); close_audio_device(device);
SDL_OutOfMemory(); 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 */ /* Start the audio thread if necessary */
switch (audio->opened) { if (!current_audio.impl.ProvidesOwnCallbackThread) {
case 1:
/* Start the audio thread */ /* Start the audio thread */
/* !!! FIXME: this is nasty. */
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
#undef SDL_CreateThread #undef SDL_CreateThread
audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL); device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL);
#else #else
audio->thread = SDL_CreateThread(SDL_RunAudio, audio); device->thread = SDL_CreateThread(SDL_RunAudio, device);
#endif #endif
if (audio->thread == NULL) { if (device->thread == NULL) {
SDL_CloseAudio(); SDL_CloseAudioDevice(id+1);
SDL_SetError("Couldn't create audio thread"); 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); return (-1);
} }
break; }
default: /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
/* The audio is now playing */ if (open_devices[0] != NULL) {
break; 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_AudioDeviceID
SDL_GetAudioStatus(void) SDL_OpenAudioDevice(const char *device, int iscapture,
const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{ {
SDL_AudioDevice *audio = current_audio; return open_audio_device(device, iscapture, desired, obtained, 2);
SDL_audiostatus status; }
status = SDL_AUDIO_STOPPED; SDL_audiostatus
if (audio && audio->enabled) { SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
if (audio->paused) { {
SDL_AudioDevice *device = get_audio_device(devid);
SDL_audiostatus status = SDL_AUDIO_STOPPED;
if (device && device->enabled) {
if (device->paused) {
status = SDL_AUDIO_PAUSED; status = SDL_AUDIO_PAUSED;
} else { } else {
status = SDL_AUDIO_PLAYING; status = SDL_AUDIO_PLAYING;
...@@ -669,74 +785,89 @@ SDL_GetAudioStatus(void) ...@@ -669,74 +785,89 @@ SDL_GetAudioStatus(void)
return (status); 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 void
SDL_PauseAudio(int pause_on) SDL_PauseAudio(int pause_on)
{ {
SDL_AudioDevice *audio = current_audio; SDL_PauseAudioDevice(1, pause_on);
}
if (audio) { void
audio->paused = pause_on; 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 void
SDL_LockAudio(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 */ /* Obtain a lock on the mixing buffers */
if (audio && audio->LockAudio) { SDL_AudioDevice *device = get_audio_device(devid);
audio->LockAudio(audio); if (device) {
current_audio.impl.UnlockDevice(device);
} }
} }
void void
SDL_UnlockAudio(void) SDL_UnlockAudio(void)
{ {
SDL_AudioDevice *audio = current_audio; SDL_UnlockAudioDevice(1);
}
/* Release lock on the mixing buffers */ void
if (audio && audio->UnlockAudio) { SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
audio->UnlockAudio(audio); {
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
close_audio_device(device);
open_devices[devid-1] = NULL;
} }
} }
void void
SDL_CloseAudio(void) SDL_CloseAudio(void)
{ {
SDL_QuitSubSystem(SDL_INIT_AUDIO); SDL_CloseAudioDevice(1);
} }
void void
SDL_AudioQuit(void) SDL_AudioQuit(void)
{ {
SDL_AudioDevice *audio = current_audio; SDL_AudioDeviceID i;
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if (audio) { SDL_CloseAudioDevice(i);
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;
} }
/* 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 #define NUM_FORMATS 10
...@@ -797,9 +928,30 @@ SDL_CalculateAudioSpec(SDL_AudioSpec * spec) ...@@ -797,9 +928,30 @@ SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
spec->silence = 0x00; spec->silence = 0x00;
break; break;
} }
spec->size = (spec->format & 0xFF) / 8; spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
spec->size *= spec->channels; spec->size *= spec->channels;
spec->size *= spec->samples; 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -159,21 +159,19 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) ...@@ -159,21 +159,19 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
float *dst = (float *) cvt->buf; float *dst = (float *) cvt->buf;
if (SDL_AUDIO_ISBIGENDIAN(format)) { if (SDL_AUDIO_ISBIGENDIAN(format)) {
for (i = cvt->len_cvt / 8; i; --i, src += 2) { for (i = cvt->len_cvt / 8; i; --i, src += 2) {
float src1, src2; const float src1 = SDL_SwapFloatBE(src[0]);
src1 = SDL_SwapFloatBE(src[0]); const float src2 = SDL_SwapFloatBE(src[1]);
src2 = SDL_SwapFloatBE(src[1]);
const double added = ((double) src1) + ((double) src2); const double added = ((double) src1) + ((double) src2);
src1 = (float) (added * 0.5); const float halved = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatBE(src1); *(dst++) = SDL_SwapFloatBE(halved);
} }
} else { } else {
for (i = cvt->len_cvt / 8; i; --i, src += 2) { for (i = cvt->len_cvt / 8; i; --i, src += 2) {
float src1, src2; const float src1 = SDL_SwapFloatLE(src[0]);
src1 = SDL_SwapFloatLE(src[0]); const float src2 = SDL_SwapFloatLE(src[1]);
src2 = SDL_SwapFloatLE(src[1]);
const double added = ((double) src1) + ((double) src2); const double added = ((double) src1) + ((double) src2);
src1 = (float) (added * 0.5); const float halved = (float) (added * 0.5);
*(dst++) = SDL_SwapFloatLE(src1); *(dst++) = SDL_SwapFloatLE(halved);
} }
} }
} }
......
...@@ -46,14 +46,63 @@ ...@@ -46,14 +46,63 @@
#define _PATH_DEV_AUDIO "/dev/audio" #define _PATH_DEV_AUDIO "/dev/audio"
#endif #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 void
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic) 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; const char *audiodev;
int audio_fd;
char audiopath[1024]; char audiopath[1024];
if (test == NULL)
test = test_stub;
/* Figure out what our audio device is */ /* Figure out what our audio device is */
if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) && if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
((audiodev = SDL_getenv("AUDIODEV")) == NULL)) { ((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
...@@ -72,111 +121,16 @@ SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic) ...@@ -72,111 +121,16 @@ SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
} }
} }
} }
audio_fd = open(audiodev, flags, 0); test_device(audiodev, flags, test, devices, devCount);
/* 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;
instance = 1; if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
do { /* Don't use errno ENOENT - it may not be thread-safe */ int instance = 0;
while (instance++ <= 64) {
SDL_snprintf(audiopath, SDL_arraysize(audiopath), SDL_snprintf(audiopath, SDL_arraysize(audiopath),
"%s%d", audiodev, instance++); "%s%d", audiodev, instance);
exists = 0; test_device(audiopath, flags, test, devices, devCount);
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;
}
} }
} }
return -1;
} }
#endif /* Audio driver selection */ #endif /* Audio driver selection */
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
/* Open the audio device, storing the pathname in 'path' */ void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic); char ***devs, int *count);
void SDL_FreeUnixAudioDevices(char ***devices, int *devCount);
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -89,21 +89,6 @@ static const Uint8 mix8[] = { ...@@ -89,21 +89,6 @@ static const Uint8 mix8[] = {
#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME) #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) #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 void
SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
......
...@@ -29,13 +29,33 @@ ...@@ -29,13 +29,33 @@
/* The SDL audio driver */ /* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice; typedef struct SDL_AudioDevice SDL_AudioDevice;
/* Define the SDL audio driver structure */
#define _THIS SDL_AudioDevice *_this #define _THIS SDL_AudioDevice *_this
#ifndef _STATUS
#define _STATUS SDL_status *status typedef struct SDL_AudioDriverImpl
#endif {
struct SDL_AudioDevice 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 */ /* The name of this audio driver */
...@@ -45,21 +65,13 @@ struct SDL_AudioDevice ...@@ -45,21 +65,13 @@ struct SDL_AudioDevice
/* The description of this audio driver */ /* The description of this audio driver */
const char *desc; const char *desc;
/* * * */ SDL_AudioDriverImpl impl;
/* Public driver functions */ } SDL_AudioDriver;
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);
/* * * */
/* 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 */ /* Data common to all devices */
...@@ -70,6 +82,7 @@ struct SDL_AudioDevice ...@@ -70,6 +82,7 @@ struct SDL_AudioDevice
SDL_AudioCVT convert; SDL_AudioCVT convert;
/* Current state flags */ /* Current state flags */
int iscapture;
int enabled; int enabled;
int paused; int paused;
int opened; int opened;
...@@ -87,10 +100,6 @@ struct SDL_AudioDevice ...@@ -87,10 +100,6 @@ struct SDL_AudioDevice
/* * * */ /* * * */
/* Data private to this driver */ /* Data private to this driver */
struct SDL_PrivateAudioData *hidden; struct SDL_PrivateAudioData *hidden;
/* * * */
/* The function used to dispose of this structure */
void (*free) (_THIS);
}; };
#undef _THIS #undef _THIS
...@@ -98,84 +107,10 @@ typedef struct AudioBootStrap ...@@ -98,84 +107,10 @@ typedef struct AudioBootStrap
{ {
const char *name; const char *name;
const char *desc; const char *desc;
int (*available) (void); int (*init) (SDL_AudioDriverImpl *impl);
SDL_AudioDevice *(*create) (int devindex); int demand_only:1; /* 1==request explicitly, or it won't be available. */
} AudioBootStrap; } 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 */ #endif /* _SDL_sysaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <signal.h> /* For kill() */ #include <signal.h> /* For kill() */
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include "SDL_timer.h" #include "SDL_timer.h"
#include "SDL_audio.h" #include "SDL_audio.h"
...@@ -32,14 +35,6 @@ ...@@ -32,14 +35,6 @@
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "SDL_alsa_audio.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 */ /* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa" #define DRIVER_NAME "alsa"
...@@ -47,182 +42,138 @@ ...@@ -47,182 +42,138 @@
/* The default ALSA audio driver */ /* The default ALSA audio driver */
#define DEFAULT_DEVICE "default" #define DEFAULT_DEVICE "default"
/* Audio driver functions */ static int (*ALSA_snd_pcm_open)
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec); (snd_pcm_t **, const char *, snd_pcm_stream_t, int);
static void ALSA_WaitAudio(_THIS); static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm);
static void ALSA_PlayAudio(_THIS); static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
static Uint8 *ALSA_GetAudioBuf(_THIS); (snd_pcm_t *,const void *, snd_pcm_uframes_t);
static void ALSA_CloseAudio(_THIS); 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 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC; static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
static void *alsa_handle = NULL; 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 int
static struct load_alsa_sym(const char *fn, void **addr)
{ {
const char *name; /*
void **func; * !!! FIXME:
} alsa_functions[] = { * Eventually, this will deal with fallbacks, version changes, and
{ * missing symbols we can workaround. But for now, it doesn't.
"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)}, { #if HAVE_DLVSYM
"snd_pcm_resume", (void **) (char *) &SDL_NAME(snd_pcm_resume)}, { *addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
"snd_pcm_prepare", (void **) (char *) &SDL_NAME(snd_pcm_prepare)}, { if (*addr == NULL)
"snd_pcm_drain", (void **) (char *) &SDL_NAME(snd_pcm_drain)}, { #endif
"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)},
{ {
"snd_pcm_hw_params_set_periods_near", (void **) (char *) *addr = dlsym(alsa_handle, fn);
&SDL_NAME(snd_pcm_hw_params_set_periods_near)}, { if (*addr == NULL) {
"snd_pcm_hw_params_get_periods", SDL_SetError("dlsym('%s') failed: %s", fn, strerror(errno));
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_periods)}, { return 0;
"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 *) return 1;
&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)}, { /* cast funcs to char* first, to please GCC's strict aliasing rules. */
"snd_pcm_sw_params", (void **) (char *) &SDL_NAME(snd_pcm_sw_params)}, { #define SDL_ALSA_SYM(x) \
"snd_pcm_nonblock", (void **) (char *) &SDL_NAME(snd_pcm_nonblock)},}; 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 static void
UnloadALSALibrary(void) UnloadALSALibrary(void)
{ {
if (alsa_loaded) { if (alsa_handle != NULL) {
/* SDL_UnloadObject(alsa_handle);*/
dlclose(alsa_handle); dlclose(alsa_handle);
alsa_handle = NULL; alsa_handle = NULL;
alsa_loaded = 0;
} }
} }
static int static int
LoadALSALibrary(void) LoadALSALibrary(void)
{ {
int i, retval = -1; int retval = 0;
if (alsa_handle == NULL) {
/* alsa_handle = SDL_LoadObject(alsa_library);*/ alsa_handle = dlopen(alsa_library, RTLD_NOW);
alsa_handle = dlopen(alsa_library, RTLD_NOW); if (alsa_handle == NULL) {
if (alsa_handle) { retval = -1;
alsa_loaded = 1; SDL_SetError("ALSA: dlopen('%s') failed: %s\n",
retval = 0; alsa_library, strerror(errno));
for (i = 0; i < SDL_arraysize(alsa_functions); i++) { } else {
/* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/ retval = load_alsa_syms();
#if HAVE_DLVSYM if (retval < 0) {
*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;
UnloadALSALibrary(); UnloadALSALibrary();
break;
} }
} }
} }
...@@ -234,12 +185,12 @@ LoadALSALibrary(void) ...@@ -234,12 +185,12 @@ LoadALSALibrary(void)
static void static void
UnloadALSALibrary(void) UnloadALSALibrary(void)
{ {
return;
} }
static int static int
LoadALSALibrary(void) LoadALSALibrary(void)
{ {
load_alsa_syms();
return 0; return 0;
} }
...@@ -262,80 +213,10 @@ get_audio_device(int channels) ...@@ -262,80 +213,10 @@ get_audio_device(int channels)
return device; 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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
ALSA_WaitAudio(_THIS) ALSA_WaitDevice(_THIS)
{ {
/* Check to see if the thread-parent process is still alive */ /* Check to see if the thread-parent process is still alive */
{ {
...@@ -343,8 +224,9 @@ ALSA_WaitAudio(_THIS) ...@@ -343,8 +224,9 @@ ALSA_WaitAudio(_THIS)
/* 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. that use a different process id for each thread.
*/ */
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ /* Check every 10 loops */
if (kill(parent, 0) < 0) { if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0; this->enabled = 0;
} }
} }
...@@ -352,13 +234,14 @@ ALSA_WaitAudio(_THIS) ...@@ -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 * http://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE * "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" * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/ */
#define SWIZ6(T) \ #define SWIZ6(T) \
T *ptr = (T *) mixbuf; \ T *ptr = (T *) this->hidden->mixbuf; \
const Uint32 count = (this->spec.samples / 6); \ const Uint32 count = (this->spec.samples / 6); \
Uint32 i; \ Uint32 i; \
for (i = 0; i < count; i++, ptr += 6) { \ for (i = 0; i < count; i++, ptr += 6) { \
...@@ -392,8 +275,8 @@ swizzle_alsa_channels_6_8bit(_THIS) ...@@ -392,8 +275,8 @@ swizzle_alsa_channels_6_8bit(_THIS)
/* /*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels * Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
* from Windows/Mac order to the format alsalib will want. * channels from Windows/Mac order to the format alsalib will want.
*/ */
static __inline__ void static __inline__ void
swizzle_alsa_channels(_THIS) swizzle_alsa_channels(_THIS)
...@@ -415,7 +298,7 @@ swizzle_alsa_channels(_THIS) ...@@ -415,7 +298,7 @@ swizzle_alsa_channels(_THIS)
static void static void
ALSA_PlayAudio(_THIS) ALSA_PlayDevice(_THIS)
{ {
int status; int status;
int sample_len; int sample_len;
...@@ -424,11 +307,12 @@ ALSA_PlayAudio(_THIS) ...@@ -424,11 +307,12 @@ ALSA_PlayAudio(_THIS)
swizzle_alsa_channels(this); swizzle_alsa_channels(this);
sample_len = this->spec.samples; sample_len = this->spec.samples;
sample_buf = (signed short *) mixbuf; sample_buf = (signed short *) this->hidden->mixbuf;
while (sample_len > 0) { while (sample_len > 0) {
status = status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
SDL_NAME(snd_pcm_writei) (pcm_handle, sample_buf, sample_len); sample_buf, sample_len);
if (status < 0) { if (status < 0) {
if (status == -EAGAIN) { if (status == -EAGAIN) {
SDL_Delay(1); SDL_Delay(1);
...@@ -437,11 +321,11 @@ ALSA_PlayAudio(_THIS) ...@@ -437,11 +321,11 @@ ALSA_PlayAudio(_THIS)
if (status == -ESTRPIPE) { if (status == -ESTRPIPE) {
do { do {
SDL_Delay(1); SDL_Delay(1);
status = SDL_NAME(snd_pcm_resume) (pcm_handle); status = ALSA_snd_pcm_resume(this->hidden->pcm_handle);
} while (status == -EAGAIN); } while (status == -EAGAIN);
} }
if (status < 0) { if (status < 0) {
status = SDL_NAME(snd_pcm_prepare) (pcm_handle); status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle);
} }
if (status < 0) { if (status < 0) {
/* Hmm, not much we can do - abort */ /* Hmm, not much we can do - abort */
...@@ -456,74 +340,89 @@ ALSA_PlayAudio(_THIS) ...@@ -456,74 +340,89 @@ ALSA_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
ALSA_GetAudioBuf(_THIS) ALSA_GetDeviceBuf(_THIS)
{ {
return (mixbuf); return (this->hidden->mixbuf);
} }
static void static void
ALSA_CloseAudio(_THIS) ALSA_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (pcm_handle) { }
SDL_NAME(snd_pcm_drain) (pcm_handle); if (this->hidden->pcm_handle) {
SDL_NAME(snd_pcm_close) (pcm_handle); ALSA_snd_pcm_drain(this->hidden->pcm_handle);
pcm_handle = NULL; ALSA_snd_pcm_close(this->hidden->pcm_handle);
this->hidden->pcm_handle = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int static int
ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec) ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
int status; int status = 0;
snd_pcm_hw_params_t *hwparams; snd_pcm_t *pcm_handle = NULL;
snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_format_t format; snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_uframes_t frames; snd_pcm_format_t format = 0;
SDL_AudioFormat test_format; 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 */ /* Open the audio device */
/* Name of device should depend on # channels in spec */ /* Name of device should depend on # channels in spec */
status = status = ALSA_snd_pcm_open(&pcm_handle,
SDL_NAME(snd_pcm_open) (&pcm_handle, get_audio_device(this->spec.channels),
get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't open audio device: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't open audio device: %s",
return (-1); ALSA_snd_strerror(status));
return 0;
} }
this->hidden->pcm_handle = pcm_handle;
/* Figure out what the hardware is capable of */ /* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams); 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) { if (status < 0) {
SDL_SetError("Couldn't get hardware config: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't get hardware config: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
/* SDL only uses interleaved sample output */ /* SDL only uses interleaved sample output */
status = status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SDL_NAME(snd_pcm_hw_params_set_access) (pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
SND_PCM_ACCESS_RW_INTERLEAVED);
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't set interleaved access: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't set interleaved access: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
/* Try for a closest match on audio format */ /* Try for a closest match on audio format */
status = -1; status = -1;
for (test_format = SDL_FirstAudioFormat(spec->format); for (test_format = SDL_FirstAudioFormat(this->spec.format);
test_format && (status < 0);) { 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) { switch (test_format) {
case AUDIO_U8: case AUDIO_U8:
format = SND_PCM_FORMAT_U8; format = SND_PCM_FORMAT_U8;
...@@ -560,131 +459,151 @@ ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -560,131 +459,151 @@ ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
break; break;
} }
if (status >= 0) { if (status >= 0) {
status = status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
SDL_NAME(snd_pcm_hw_params_set_format) (pcm_handle, hwparams, format);
hwparams, format);
} }
if (status < 0) { if (status < 0) {
test_format = SDL_NextAudioFormat(); test_format = SDL_NextAudioFormat();
} }
} }
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't find any hardware audio formats"); ALSA_CloseDevice(this);
ALSA_CloseAudio(this); SDL_SetError("ALSA: Couldn't find any hardware audio formats");
return (-1); return 0;
} }
spec->format = test_format; this->spec.format = test_format;
/* Set the number of channels */ /* Set the number of channels */
status = status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
SDL_NAME(snd_pcm_hw_params_set_channels) (pcm_handle, hwparams, this->spec.channels);
spec->channels);
if (status < 0) { 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)) { if ((status <= 0) || (status > 2)) {
SDL_SetError("Couldn't set audio channels"); ALSA_CloseDevice(this);
ALSA_CloseAudio(this); SDL_SetError("ALSA: Couldn't set audio channels");
return (-1); return 0;
} }
spec->channels = status; this->spec.channels = status;
} }
/* Set the audio rate */ /* Set the audio rate */
status = status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
SDL_NAME(snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams, this->spec.freq, NULL);
spec->freq, NULL);
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't set audio frequency: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't set audio frequency: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
spec->freq = status; this->spec.freq = status;
/* Set the buffer size, in samples */ /* Set the buffer size, in samples */
frames = spec->samples; frames = this->spec.samples;
frames = frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
SDL_NAME(snd_pcm_hw_params_set_period_size_near) (pcm_handle, frames, NULL);
hwparams, frames, this->spec.samples = frames;
NULL); ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);
spec->samples = frames;
SDL_NAME(snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2,
NULL);
/* "set" the hardware with the desired parameters */ /* "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) { if (status < 0) {
SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
/* This is useful for debugging... */ #if AUDIO_DEBUG
/* {
{ snd_pcm_sframes_t bufsize; int fragments; snd_pcm_sframes_t bufsize;
bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams); int fragments;
fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams); 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); fprintf(stderr,"ALSA: bufsize = %ld, fragments = %d\n",bufsize,fragments);
} }
*/ #endif
/* Set the software parameters */ /* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams); 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) { if (status < 0) {
SDL_SetError("Couldn't get software config: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't get software config: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
status = status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0);
SDL_NAME(snd_pcm_sw_params_set_start_threshold) (pcm_handle,
swparams, 0);
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't set start threshold: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("ALSA: Couldn't set start threshold: %s",
ALSA_CloseAudio(this); ALSA_snd_strerror(status));
return (-1); return 0;
} }
status = status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
SDL_NAME(snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams,
frames);
if (status < 0) { if (status < 0) {
SDL_SetError("Couldn't set avail min: %s", ALSA_CloseDevice(this);
SDL_NAME(snd_strerror) (status)); SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
ALSA_CloseAudio(this); return 0;
return (-1);
} }
status = SDL_NAME(snd_pcm_sw_params) (pcm_handle, swparams); status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
if (status < 0) { if (status < 0) {
ALSA_CloseDevice(this);
SDL_SetError("Couldn't set software audio parameters: %s", SDL_SetError("Couldn't set software audio parameters: %s",
SDL_NAME(snd_strerror) (status)); ALSA_snd_strerror(status));
ALSA_CloseAudio(this); return 0;
return (-1);
} }
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
ALSA_CloseAudio(this); ALSA_CloseDevice(this);
return (-1); 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) */ /* 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 */ /* 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. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -46,11 +46,5 @@ struct SDL_PrivateAudioData ...@@ -46,11 +46,5 @@ struct SDL_PrivateAudioData
int mixlen; 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 */ #endif /* _ALSA_PCM_audio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* 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 @@ ...@@ -27,7 +27,6 @@
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_artsaudio.h" #include "SDL_artsaudio.h"
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
...@@ -40,19 +39,12 @@ ...@@ -40,19 +39,12 @@
/* The tag name used by artsc audio */ /* The tag name used by artsc audio */
#define ARTS_DRIVER_NAME "arts" #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 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
static void *arts_handle = NULL; 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 int (*SDL_NAME(arts_init)) (void);
static void (*SDL_NAME(arts_free)) (void); static void (*SDL_NAME(arts_free)) (void);
static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, 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, ...@@ -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, static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
int count); 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 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 static struct
{ {
const char *name; const char *name;
void **func; void **func;
} arts_functions[] = { } arts_functions[] = {
{ SDL_ARTS_SYM(arts_init),
"arts_init", (void **) &SDL_NAME(arts_init)}, { SDL_ARTS_SYM(arts_free),
"arts_free", (void **) &SDL_NAME(arts_free)}, { SDL_ARTS_SYM(arts_play_stream),
"arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, { SDL_ARTS_SYM(arts_stream_set),
"arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, { SDL_ARTS_SYM(arts_stream_get),
"arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, { SDL_ARTS_SYM(arts_write),
"arts_write", (void **) &SDL_NAME(arts_write)}, { SDL_ARTS_SYM(arts_close_stream),
"arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},}; SDL_ARTS_SYM(arts_error_text),
};
#undef SDL_ARTS_SYM
static void static void
UnloadARTSLibrary() UnloadARTSLibrary()
{ {
if (arts_loaded) { if (arts_handle != NULL) {
SDL_UnloadObject(arts_handle); SDL_UnloadObject(arts_handle);
arts_handle = NULL; arts_handle = NULL;
arts_loaded = 0;
} }
} }
...@@ -95,20 +91,22 @@ LoadARTSLibrary(void) ...@@ -95,20 +91,22 @@ LoadARTSLibrary(void)
{ {
int i, retval = -1; int i, retval = -1;
arts_handle = SDL_LoadObject(arts_library); if (arts_handle == NULL) {
if (arts_handle) { arts_handle = SDL_LoadObject(arts_library);
arts_loaded = 1; if (arts_handle != NULL) {
retval = 0; retval = 0;
for (i = 0; i < SDL_arraysize(arts_functions); ++i) { for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
*arts_functions[i].func = *arts_functions[i].func =
SDL_LoadFunction(arts_handle, arts_functions[i].name); SDL_LoadFunction(arts_handle, arts_functions[i].name);
if (!*arts_functions[i].func) { if (!*arts_functions[i].func) {
retval = -1; retval = -1;
UnloadARTSLibrary(); UnloadARTSLibrary();
break; break;
}
} }
} }
} }
return retval; return retval;
} }
...@@ -128,117 +126,45 @@ LoadARTSLibrary(void) ...@@ -128,117 +126,45 @@ LoadARTSLibrary(void)
#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ #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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
ARTS_WaitAudio(_THIS) ARTS_WaitDevice(_THIS)
{ {
Sint32 ticks; Sint32 ticks;
/* Check to see if the thread-parent process is still alive */ /* Check to see if the thread-parent process is still alive */
{ {
static int cnt = 0; 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. that use a different process id for each thread.
*/ */
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ /* Check every 10 loops */
if (kill(parent, 0) < 0) { if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0; this->enabled = 0;
} }
} }
} }
/* Use timer for general audio synchronization */ /* 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) { if (ticks > 0) {
SDL_Delay(ticks); SDL_Delay(ticks);
} }
} }
static void static void
ARTS_PlayAudio(_THIS) ARTS_PlayDevice(_THIS)
{ {
int written;
/* Write the audio data */ /* 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 timer synchronization is enabled, set the next write frame */
if (frame_ticks) { if (this->hidden->frame_ticks) {
next_frame += frame_ticks; this->hidden->next_frame += this->hidden->frame_ticks;
} }
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
...@@ -250,41 +176,57 @@ ARTS_PlayAudio(_THIS) ...@@ -250,41 +176,57 @@ ARTS_PlayAudio(_THIS)
#endif #endif
} }
static void
ARTS_WaitDone(_THIS)
{
/* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
}
static Uint8 * static Uint8 *
ARTS_GetAudioBuf(_THIS) ARTS_GetDeviceBuf(_THIS)
{ {
return (mixbuf); return (this->hidden->mixbuf);
} }
static void static void
ARTS_CloseAudio(_THIS) ARTS_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (stream) { }
SDL_NAME(arts_close_stream) (stream); if (this->hidden->stream) {
stream = 0; 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 static int
ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
int bits, frag_spec; int rc = 0;
SDL_AudioFormat test_format, format; int bits = 0, frag_spec = 0;
SDL_AudioFormat test_format = 0, format = 0;
/* Reset the timer synchronization flag */
frame_ticks = 0.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 */ /* Try for a closest match on audio format */
format = 0; for (test_format = SDL_FirstAudioFormat(this->spec.format);
bits = 0;
for (test_format = SDL_FirstAudioFormat(spec->format);
!format && test_format;) { !format && test_format;) {
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format); fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
...@@ -307,51 +249,108 @@ ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -307,51 +249,108 @@ ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
} }
if (format == 0) { if (format == 0) {
ARTS_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats"); 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) { if ((rc = SDL_NAME(arts_init) ()) != 0) {
SDL_SetError("Unable to initialize ARTS"); ARTS_CloseDevice(this);
return (-1); SDL_SetError( "Unable to initialize ARTS: %s",
SDL_NAME(arts_error_text)(rc) );
return 0;
} }
stream = this->hidden->stream = SDL_NAME(arts_play_stream) (
SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL"); this->spec.freq,
bits, this->spec.channels,
"SDL");
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */ /* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != spec->size) { if ((0x01 << frag_spec) != this->spec.size) {
ARTS_CloseDevice(this);
SDL_SetError("Fragment size must be a power of two"); SDL_SetError("Fragment size must be a power of two");
return (-1); return 0;
} }
frag_spec |= 0x00020000; /* two fragments, for low latency */ frag_spec |= 0x00020000; /* two fragments, for low latency */
#ifdef ARTS_P_PACKET_SETTINGS #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 #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); 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 #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 */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return (-1); 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) */ /* 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. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -49,13 +49,5 @@ struct SDL_PrivateAudioData ...@@ -49,13 +49,5 @@ struct SDL_PrivateAudioData
}; };
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #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 */ #endif /* _SDL_artscaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -36,138 +36,81 @@ extern "C" ...@@ -36,138 +36,81 @@ extern "C"
#include "../../thread/beos/SDL_systhread_c.h" #include "../../thread/beos/SDL_systhread_c.h"
#include "SDL_beaudio.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 */ /* !!! FIXME: have the callback call the higher level to avoid code dupe. */
/* The BeOS callback for handling the audio buffer */
static int Audio_Available(void) static void
{ FillSound(void *device, void *stream, size_t len,
return (1); const media_raw_audio_format & format)
} {
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
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;
return device; /* Silence the buffer, since it's ours */
} SDL_memset(stream, audio->spec.silence, len);
AudioBootStrap BAUDIO_bootstrap = { /* Only do soemthing if audio is enabled */
"baudio", "BeOS BSoundPlayer", if (!audio->enabled)
Audio_Available, Audio_CreateDevice return;
};
/* The BeOS callback for handling the audio buffer */ if (!audio->paused) {
static void FillSound(void *device, void *stream, size_t len, if (audio->convert.needed) {
const media_raw_audio_format & format) SDL_mutexP(audio->mixer_lock);
{ (*audio->spec.callback) (audio->spec.userdata,
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,
(Uint8 *) audio->convert.buf, (Uint8 *) audio->convert.buf,
audio->convert.len); audio->convert.len);
SDL_mutexV(audio->mixer_lock); SDL_mutexV(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert); SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream, audio->convert.buf, SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
audio->convert.len_cvt); } else {
} else { SDL_mutexP(audio->mixer_lock);
SDL_mutexP(audio->mixer_lock); (*audio->spec.callback) (audio->spec.userdata,
(*audio->spec.callback) (audio->spec.userdata, (Uint8 *) stream, len);
(Uint8 *) stream, len); SDL_mutexV(audio->mixer_lock);
SDL_mutexV(audio->mixer_lock);
}
} }
return;
} }
}
/* Dummy functions -- we don't use thread-based audio */ static void
void BE_WaitAudio(_THIS) BEOSAUDIO_CloseDevice(_THIS)
{ {
return; if (_this->hidden != NULL) {
} if (_this->hidden->audio_obj) {
void BE_PlayAudio(_THIS) _this->hidden->audio_obj->Stop();
{ delete _this->hidden->audio_obj;
return; _this->hidden->audio_obj = NULL;
}
Uint8 *BE_GetAudioBuf(_THIS)
{
return (NULL);
}
void BE_CloseAudio(_THIS)
{
if (audio_obj) {
audio_obj->Stop();
delete audio_obj;
audio_obj = NULL;
} }
/* Quit the Be Application, if there's nothing left to do */ delete _this->hidden;
SDL_QuitBeApp(); _this->hidden = NULL;
} }
}
int BE_OpenAudio(_THIS, SDL_AudioSpec * spec) static int
{ BEOSAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
int valid_datatype = 0; {
media_raw_audio_format format; int valid_datatype = 0;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format); media_raw_audio_format format;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
/* Parse the audio format and fill the Be raw audio format */
memset(&format, '\0', sizeof(media_raw_audio_format)); /* Initialize all variables that we clean on shutdown */
format.byte_order = B_MEDIA_LITTLE_ENDIAN; _this->hidden = new SDL_PrivateAudioData;
format.frame_rate = (float) spec->freq; if (_this->hidden == NULL) {
format.channel_count = spec->channels; /* !!! FIXME: support > 2? */ SDL_OutOfMemory();
while ((!valid_datatype) && (test_format)) { return 0;
valid_datatype = 1; }
spec->format = test_format; SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
switch (test_format) {
/* 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: case AUDIO_S8:
format.format = media_raw_audio_format::B_AUDIO_CHAR; format.format = media_raw_audio_format::B_AUDIO_CHAR;
break; break;
...@@ -207,43 +150,67 @@ extern "C" ...@@ -207,43 +150,67 @@ extern "C"
valid_datatype = 0; valid_datatype = 0;
test_format = SDL_NextAudioFormat(); test_format = SDL_NextAudioFormat();
break; break;
}
} }
}
format.buffer_size = spec->samples; format.buffer_size = _this->spec.samples;
if (!valid_datatype) { /* shouldn't happen, but just in case... */ if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format"); BEOSAUDIO_CloseDevice(_this);
return (-1); SDL_SetError("Unsupported audio format");
} return 0;
}
/* Initialize the Be Application, if it's not already started */ /* Calculate the final parameters for this audio specification */
if (SDL_InitBeApp() < 0) { SDL_CalculateAudioSpec(&_this->spec);
return (-1);
} /* 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 */ /* We're running! */
SDL_CalculateAudioSpec(spec); return 1;
}
/* Subscribe to the audio stream (creates a new thread) */ static void
{ BEOSAUDIO_Deinitialize(void)
sigset_t omask; {
SDL_MaskSignals(&omask); SDL_QuitBeApp();
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);
}
/* We're running! */ static int
return (1); 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_beaudio_h
#define _SDL_lowaudio_h #define _SDL_beaudio_h
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -34,8 +34,6 @@ struct SDL_PrivateAudioData ...@@ -34,8 +34,6 @@ struct SDL_PrivateAudioData
BSoundPlayer *audio_obj; BSoundPlayer *audio_obj;
}; };
/* Old variable names */ #endif /* _SDL_beaudio_h */
#define audio_obj (_this->hidden->audio_obj)
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -61,95 +61,152 @@ ...@@ -61,95 +61,152 @@
/* #define DEBUG_AUDIO_STREAM */ /* #define DEBUG_AUDIO_STREAM */
#ifdef USE_BLOCKING_WRITES #ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS O_WRONLY #define OPEN_FLAGS_OUTPUT O_WRONLY
#define OPEN_FLAGS_INPUT O_RDONLY
#else #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 #endif
/* Audio driver functions */ /* !!! FIXME: so much cut and paste with dsp/dma drivers... */
static void OBSD_WaitAudio(_THIS); static char **outputDevices = NULL;
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec); static int outputDeviceCount = 0;
static void OBSD_PlayAudio(_THIS); static char **inputDevices = NULL;
static Uint8 *OBSD_GetAudioBuf(_THIS); static int inputDeviceCount = 0;
static void OBSD_CloseAudio(_THIS);
#ifdef DEBUG_AUDIO static inline void
static void OBSD_Status(_THIS); free_device_list(char ***devs, int *count)
#endif {
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 static inline void
Audio_Available(void) build_device_lists(void)
{ {
int fd; build_device_list(0, &outputDevices, &outputDeviceCount);
int available; build_device_list(1, &inputDevices, &inputDeviceCount);
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
available = 1;
close(fd);
}
return (available);
} }
static void
Audio_DeleteDevice(SDL_AudioDevice * device) static inline void
free_device_lists(void)
{ {
SDL_free(device->hidden); free_device_list(&outputDevices, &outputDeviceCount);
SDL_free(device); 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)); static int
if (this) { BSDAUDIO_DetectDevices(int iscapture)
SDL_memset(this, 0, (sizeof *this)); {
this->hidden = (struct SDL_PrivateAudioData *) if (iscapture) {
SDL_malloc((sizeof *this->hidden)); 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(); return 0; /* shouldn't ever hit this. */
if (this) }
SDL_free(this);
return (0); 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 */ SDL_SetError("No such device");
this->OpenAudio = OBSD_OpenAudio; return NULL;
this->WaitAudio = OBSD_WaitAudio; }
this->PlayAudio = OBSD_PlayAudio;
this->GetAudioBuf = OBSD_GetAudioBuf;
this->CloseAudio = OBSD_CloseAudio; 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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
OBSD_WaitAudio(_THIS) BSDAUDIO_WaitDevice(_THIS)
{ {
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */ #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */ /* See if we need to use timed audio synchronization */
if (frame_ticks) { if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */ /* Use timer for general audio synchronization */
Sint32 ticks; Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
if (ticks > 0) { if (ticks > 0) {
SDL_Delay(ticks); SDL_Delay(ticks);
} }
...@@ -159,13 +216,13 @@ OBSD_WaitAudio(_THIS) ...@@ -159,13 +216,13 @@ OBSD_WaitAudio(_THIS)
struct timeval timeout; struct timeval timeout;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset); FD_SET(this->hidden->audio_fd, &fdset);
timeout.tv_sec = 10; timeout.tv_sec = 10;
timeout.tv_usec = 0; timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n"); fprintf(stderr, "Waiting for audio to get ready\n");
#endif #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 = const char *message =
"Audio timeout - buggy audio driver? (disabled)"; "Audio timeout - buggy audio driver? (disabled)";
/* In general we should never print to the screen, /* In general we should never print to the screen,
...@@ -175,7 +232,7 @@ OBSD_WaitAudio(_THIS) ...@@ -175,7 +232,7 @@ OBSD_WaitAudio(_THIS)
fprintf(stderr, "SDL: %s\n", message); fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0; this->enabled = 0;
/* Don't try to close - may hang */ /* Don't try to close - may hang */
audio_fd = -1; this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n"); fprintf(stderr, "Done disabling audio\n");
#endif #endif
...@@ -188,13 +245,16 @@ OBSD_WaitAudio(_THIS) ...@@ -188,13 +245,16 @@ OBSD_WaitAudio(_THIS)
} }
static void static void
OBSD_PlayAudio(_THIS) BSDAUDIO_PlayDevice(_THIS)
{ {
int written, p = 0; int written, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */ /* Write the audio data, checking for EAGAIN on broken audio drivers */
do { 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) if (written > 0)
p += written; p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) { if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
...@@ -211,8 +271,8 @@ OBSD_PlayAudio(_THIS) ...@@ -211,8 +271,8 @@ OBSD_PlayAudio(_THIS)
while (p < written); while (p < written);
/* If timer synchronization is enabled, set the next write frame */ /* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) { if (this->hidden->frame_ticks) {
next_frame += frame_ticks; this->hidden->next_frame += this->hidden->frame_ticks;
} }
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
...@@ -225,141 +285,77 @@ OBSD_PlayAudio(_THIS) ...@@ -225,141 +285,77 @@ OBSD_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
OBSD_GetAudioBuf(_THIS) BSDAUDIO_GetDeviceBuf(_THIS)
{ {
return (mixbuf); return (this->hidden->mixbuf);
} }
static void static void
OBSD_CloseAudio(_THIS) BSDAUDIO_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_fd >= 0) { }
close(audio_fd); if (this->hidden->audio_fd >= 0) {
audio_fd = -1; close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
#ifdef DEBUG_AUDIO static int
void BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
OBSD_Status(_THIS)
{ {
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
audio_info_t info; audio_info_t info;
if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) { /* We don't care what the devname is...we'll try to open anything. */
fprintf(stderr, "AUDIO_GETINFO failed.\n"); /* ...but default to first name in the list... */
return; 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" /* Initialize all variables that we clean on shutdown */
"[play/record info]\n" this->hidden = (struct SDL_PrivateAudioData *)
"buffer size : %d bytes\n" SDL_malloc((sizeof *this->hidden));
"sample rate : %i Hz\n" if (this->hidden == NULL) {
"channels : %i\n" SDL_OutOfMemory();
"precision : %i-bit\n" return 0;
"encoding : 0x%x\n" }
"seek : %i\n" SDL_memset(this->hidden, 0, (sizeof *this->hidden));
"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 */
static int /* Open the audio device */
OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec) this->hidden->audio_fd = open(devname, flags, 0);
{ if (this->hidden->audio_fd < 0) {
char audiodev[64]; SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
SDL_AudioFormat format; return 0;
audio_info_t info; }
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->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);
}
/* Set to play mode */ /* Set to play mode */
info.mode = AUMODE_PLAY; 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"); SDL_SetError("Couldn't put device into play mode");
return (-1); return 0;
} }
mixbuf = NULL;
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(spec->format); for (format = SDL_FirstAudioFormat(this->spec.format);
format; format = SDL_NextAudioFormat()) { format; format = SDL_NextAudioFormat()) {
switch (format) { switch (format) {
case AUDIO_U8: case AUDIO_U8:
...@@ -389,46 +385,69 @@ OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -389,46 +385,69 @@ OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
default: default:
continue; continue;
} }
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
break; break;
}
} }
if (!format) { if (!format) {
SDL_SetError("No supported encoding for 0x%x", spec->format); BSDAUDIO_CloseDevice(this);
return (-1); SDL_SetError("No supported encoding for 0x%x", this->spec.format);
return 0;
} }
spec->format = format; this->spec.format = format;
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
info.play.channels = spec->channels; info.play.channels = this->spec.channels;
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1) if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
spec->channels = 1; this->spec.channels = 1;
}
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
info.play.sample_rate = spec->freq; info.play.sample_rate = this->spec.freq;
info.blocksize = spec->size; info.blocksize = this->spec.size;
info.hiwat = 5; info.hiwat = 5;
info.lowat = 3; info.lowat = 3;
(void) ioctl(audio_fd, AUDIO_SETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(audio_fd, AUDIO_GETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
spec->freq = info.play.sample_rate; this->spec.freq = info.play.sample_rate;
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return (-1); 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) */ BSDAUDIO_Status(this);
parent = getpid();
#ifdef DEBUG_AUDIO
OBSD_Status(this);
#endif
/* We're ready to rock and roll. :-) */ /* We're ready to rock and roll. :-) */
return (0); 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_openbsdaudio_h #ifndef _SDL_bsdaudio_h
#define _SDL_openbsdaudio_h #define _SDL_bsdaudio_h
#include "../SDL_sysaudio.h" #include "../SDL_sysaudio.h"
...@@ -47,13 +47,6 @@ struct SDL_PrivateAudioData ...@@ -47,13 +47,6 @@ struct SDL_PrivateAudioData
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */ #endif /* _SDL_bsdaudio_h */
#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_openbsdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -42,10 +42,10 @@ typedef struct _tMixBufferDesc ...@@ -42,10 +42,10 @@ typedef struct _tMixBufferDesc
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// DARTEventFunc // 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... // playback of a buffer, etc...
//--------------------------------------------------------------------- //---------------------------------------------------------------------
LONG APIENTRY static LONG APIENTRY
DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
{ {
if (ulFlags && MIX_WRITE_COMPLETE) { // Playback of buffer completed! if (ulFlags && MIX_WRITE_COMPLETE) { // Playback of buffer completed!
...@@ -71,13 +71,12 @@ DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) ...@@ -71,13 +71,12 @@ DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
} }
int static int
DART_OpenAudio(_THIS, SDL_AudioSpec * spec) 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; int valid_datatype = 0;
MCI_AMP_OPEN_PARMS AmpOpenParms; MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
int iDeviceOrd = 0; // Default device to be used int iDeviceOrd = 0; // Default device to be used
int bOpenShared = 1; // Try opening it shared int bOpenShared = 1; // Try opening it shared
int iBits = 16; // Default is 16 bits signed int iBits = 16; // Default is 16 bits signed
...@@ -89,6 +88,15 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -89,6 +88,15 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
int iSilence; int iSilence;
int rc; 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! // First thing is to try to open a given DART device!
SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS)); SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
// pszDeviceType should contain the device type in low word, and device ordinal in high word! // 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) ...@@ -100,30 +108,34 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
iOpenMode |= MCI_OPEN_SHAREABLE; iOpenMode |= MCI_OPEN_SHAREABLE;
rc = mciSendCommand(0, MCI_OPEN, iOpenMode, (PVOID) & AmpOpenParms, 0); rc = mciSendCommand(0, MCI_OPEN, iOpenMode, (PVOID) & AmpOpenParms, 0);
if (rc != MCIERR_SUCCESS) // No audio available?? if (rc != MCIERR_SUCCESS) { // No audio available??
return (-1); DART_CloseDevice(_this);
SDL_SetError("DART: Couldn't open audio device.");
return 0;
}
// Save the device ID we got from DART! // Save the device ID we got from DART!
// We will use this in the next calls! // We will use this in the next calls!
iDeviceOrd = AmpOpenParms.usDeviceID; _this->hidden->iCurrDeviceOrd = iDeviceOrd = AmpOpenParms.usDeviceID;
// Determine the audio parameters from the AudioSpec // Determine the audio parameters from the AudioSpec
if (spec->channels > 2) if (_this->spec.channels > 4)
spec->channels = 2; // !!! FIXME: more than stereo support in OS/2? _this->spec.channels = 4;
while ((!valid_datatype) && (test_format)) { while ((!valid_datatype) && (test_format)) {
spec->format = test_format; _this->spec.format = test_format;
valid_datatype = 1; valid_datatype = 1;
switch (test_format) { switch (test_format) {
case AUDIO_U8: case AUDIO_U8:
// Unsigned 8 bit audio data // Unsigned 8 bit audio data
iSilence = 0x80; iSilence = 0x80;
iBits = 8; _this->hidden->iCurrBits = iBits = 8;
break; break;
case AUDIO_S16LSB: case AUDIO_S16LSB:
// Signed 16 bit audio data // Signed 16 bit audio data
iSilence = 0x00; iSilence = 0x00;
iBits = 16; _this->hidden->iCurrBits = iBits = 16;
break; break;
// !!! FIXME: int32? // !!! FIXME: int32?
...@@ -137,16 +149,16 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -137,16 +149,16 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (!valid_datatype) { // shouldn't happen, but just in case... if (!valid_datatype) { // shouldn't happen, but just in case...
// Close DART, and exit with error code! // Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0); DART_CloseDevice(_this);
SDL_SetError("Unsupported audio format"); SDL_SetError("Unsupported audio format");
return (-1); return 0;
} }
iFreq = spec->freq; _this->hidden->iCurrFreq = iFreq = _this->spec.freq;
iChannels = spec->channels; _this->hidden->iCurrChannels = iChannels = _this->spec.channels;
/* Update the fragment size as size in bytes */ /* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&_this->spec);
iBufSize = spec->size; _this->hidden->iCurrBufSize = iBufSize = _this->spec.size;
// Now query this device if it supports the given freq/bits/channels! // Now query this device if it supports the given freq/bits/channels!
SDL_memset(&(_this->hidden->MixSetupParms), 0, SDL_memset(&(_this->hidden->MixSetupParms), 0,
...@@ -163,9 +175,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -163,9 +175,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
&(_this->hidden->MixSetupParms), 0); &(_this->hidden->MixSetupParms), 0);
if (rc != MCIERR_SUCCESS) { // The device cannot handle this format! if (rc != MCIERR_SUCCESS) { // The device cannot handle this format!
// Close DART, and exit with error code! // 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"); SDL_SetError("Audio device doesn't support requested audio format");
return (-1); return 0;
} }
// The device can handle this format, so initialize! // The device can handle this format, so initialize!
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP, rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
...@@ -173,9 +185,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -173,9 +185,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
&(_this->hidden->MixSetupParms), 0); &(_this->hidden->MixSetupParms), 0);
if (rc != MCIERR_SUCCESS) { // The device could not be opened! if (rc != MCIERR_SUCCESS) { // The device could not be opened!
// Close DART, and exit with error code! // 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"); SDL_SetError("Audio device could not be set up");
return (-1); return 0;
} }
// Ok, the device is initialized. // Ok, the device is initialized.
// Now we should allocate buffers. For this, we need a place where // Now we should allocate buffers. For this, we need a place where
...@@ -184,9 +196,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -184,9 +196,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
(MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER) * iNumBufs); (MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER) * iNumBufs);
if (!(_this->hidden->pMixBuffers)) { // Not enough memory! if (!(_this->hidden->pMixBuffers)) { // Not enough memory!
// Close DART, and exit with error code! // Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0); DART_CloseDevice(_this);
SDL_SetError("Not enough memory for audio buffer descriptors"); SDL_OutOfMemory();
return (-1); return 0;
} }
// Now that we have the place for buffer list, we can ask DART for the // Now that we have the place for buffer list, we can ask DART for the
// buffers! // buffers!
...@@ -201,12 +213,12 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -201,12 +213,12 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|| (iNumBufs != _this->hidden->BufferParms.ulNumBuffers) || (iNumBufs != _this->hidden->BufferParms.ulNumBuffers)
|| (_this->hidden->BufferParms.ulBufferSize == 0)) { // Could not allocate memory! || (_this->hidden->BufferParms.ulBufferSize == 0)) { // Could not allocate memory!
// Close DART, and exit with error code! // Close DART, and exit with error code!
SDL_free(_this->hidden->pMixBuffers); DART_CloseDevice(_this);
_this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("DART could not allocate buffers"); 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! // Ok, we have all the buffers allocated, let's mark them!
{ {
int i; int i;
...@@ -216,24 +228,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -216,24 +228,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
// Check if this buffer was really allocated by DART // Check if this buffer was really allocated by DART
if ((!(_this->hidden->pMixBuffers[i].pBuffer)) if ((!(_this->hidden->pMixBuffers[i].pBuffer))
|| (!pBufferDesc)) { // Wrong buffer! || (!pBufferDesc)) { // Wrong buffer!
// Close DART, and exit with error code! DART_CloseDevice(_this);
// 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);
SDL_SetError("Error at internal buffer check"); SDL_SetError("Error at internal buffer check");
return (-1); return 0;
} }
pBufferDesc->iBufferUsage = BUFFER_EMPTY; pBufferDesc->iBufferUsage = BUFFER_EMPTY;
pBufferDesc->pSDLAudioDevice = _this; pBufferDesc->pSDLAudioDevice = _this;
...@@ -254,43 +251,41 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -254,43 +251,41 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (DosCreateEventSem if (DosCreateEventSem
(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE) != NO_ERROR) (NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE) != NO_ERROR)
{ {
// Could not create event semaphore! DART_CloseDevice(_this);
{
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);
SDL_SetError("Could not create event semaphore"); 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;
} }
static void
void
DART_ThreadInit(_THIS) 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 */ /* This function waits until it is possible to write a full sound buffer */
void static void
DART_WaitAudio(_THIS) DART_WaitDevice(_THIS)
{ {
int i; int i;
pMixBufferDesc pBufDesc; pMixBufferDesc pBufDesc;
...@@ -308,8 +303,8 @@ DART_WaitAudio(_THIS) ...@@ -308,8 +303,8 @@ DART_WaitAudio(_THIS)
return; return;
} }
void static void
DART_PlayAudio(_THIS) DART_PlayDevice(_THIS)
{ {
int iFreeBuf = _this->hidden->iNextFreeBuffer; int iFreeBuf = _this->hidden->iNextFreeBuffer;
pMixBufferDesc pBufDesc; pMixBufferDesc pBufDesc;
...@@ -328,8 +323,8 @@ DART_PlayAudio(_THIS) ...@@ -328,8 +323,8 @@ DART_PlayAudio(_THIS)
_this->hidden->iNextFreeBuffer = iFreeBuf; _this->hidden->iNextFreeBuffer = iFreeBuf;
} }
Uint8 * static Uint8 *
DART_GetAudioBuf(_THIS) DART_GetDeviceBuf(_THIS)
{ {
int iFreeBuf; int iFreeBuf;
Uint8 *pResult; Uint8 *pResult;
...@@ -348,125 +343,110 @@ DART_GetAudioBuf(_THIS) ...@@ -348,125 +343,110 @@ DART_GetAudioBuf(_THIS)
return pResult; return pResult;
} }
} else } else
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n", printf("[DART_GetDeviceBuf] : ERROR! pBufDesc = %p\n",
pBufDesc); pBufDesc);
} else } else
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n", printf("[DART_GetDeviceBuf] : ERROR! _this->hidden = %p\n",
_this->hidden); _this->hidden);
} else } else
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this); printf("[DART_GetDeviceBuf] : ERROR! _this = %p\n", _this);
return NULL; return NULL;
} }
void static void
DART_WaitDone(_THIS) DART_WaitDone(_THIS)
{ {
pMixBufferDesc pBufDesc; pMixBufferDesc pBufDesc;
ULONG ulPostCount; ULONG ulPostCount = 0;
APIRET rc; 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)) { while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc == NO_ERROR)) {
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount); DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important! rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
} }
} }
void static void
DART_CloseAudio(_THIS) DART_CloseDevice(_THIS)
{ {
MCI_GENERIC_PARMS GenericParms; MCI_GENERIC_PARMS GenericParms;
int rc; int rc;
int i;
// Stop DART playback if (_this->hidden != NULL) {
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT, // Stop DART playback
&GenericParms, 0); if (_this->hidden->iCurrDeviceOrd) {
if (rc != MCIERR_SUCCESS) { rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP,
MCI_WAIT, &GenericParms, 0);
#ifdef SFX_DEBUG_BUILD #ifdef SFX_DEBUG_BUILD
printf("Could not stop DART playback!\n"); if (rc != MCIERR_SUCCESS) {
fflush(stdout); printf("Could not stop DART playback!\n");
fflush(stdout);
}
#endif #endif
} }
// Close event semaphore
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
// Free memory of buffer descriptions // Close event semaphore
{ if (_this->hidden->hevAudioBufferPlayed) {
int i; DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
for (i = 0; i < _this->hidden->iCurrNumBufs; i++) _this->hidden->hevAudioBufferPlayed = 0;
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm)); }
}
// Deallocate buffers // Free memory of buffer descriptions
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER, for (i = 0; i < _this->hidden->iCurrNumBufs; i++) {
MCI_WAIT | MCI_DEALLOCATE_MEMORY, SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
&(_this->hidden->BufferParms), 0); _this->hidden->pMixBuffers[i].ulUserParm = 0;
}
_this->hidden->iCurrNumBufs = 0;
// Free bufferlist // Deallocate buffers
SDL_free(_this->hidden->pMixBuffers); if (_this->hidden->iCurrDeviceOrd) {
_this->hidden->pMixBuffers = NULL; rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
}
// Close dart // Free bufferlist
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT, if (_this->hidden->pMixBuffers != NULL) {
&(GenericParms), 0); 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 SDL_free(_this->hidden);
Audio_Available(void) _this->hidden = NULL;
{ }
return (1);
} }
void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
}
SDL_AudioDevice * static int
Audio_CreateDevice(int devindex) 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 */ /* Set the function pointers */
this->OpenAudio = DART_OpenAudio; impl->OpenDevice = DART_OpenDevice;
this->ThreadInit = DART_ThreadInit; impl->ThreadInit = DART_ThreadInit;
this->WaitAudio = DART_WaitAudio; impl->WaitDevice = DART_WaitDevice;
this->PlayAudio = DART_PlayAudio; impl->GetDeviceBuf = DART_GetDeviceBuf;
this->GetAudioBuf = DART_GetAudioBuf; impl->PlayDevice = DART_PlayDevice;
this->WaitDone = DART_WaitDone; impl->WaitDone = DART_WaitDone;
this->CloseAudio = DART_CloseAudio; impl->CloseDevice = DART_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this right? */
this->free = Audio_DeleteDevice;
return 1;
return this;
} }
AudioBootStrap DART_bootstrap = { AudioBootStrap DART_bootstrap = {
"dart", "OS/2 Direct Audio RouTines (DART)", "dart", "OS/2 Direct Audio RouTines (DART)", DART_Init, 0
Audio_Available, Audio_CreateDevice
}; };
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,14 +21,15 @@ ...@@ -21,14 +21,15 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_dart_h
#define _SDL_lowaudio_h #define _SDL_dart_h
#define INCL_TYPES #define INCL_TYPES
#define INCL_DOSSEMAPHORES #define INCL_DOSSEMAPHORES
#define INCL_DOSRESOURCES #define INCL_DOSRESOURCES
#define INCL_DOSMISC #define INCL_DOSMISC
#define INCL_DOSERRORS #define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_OS2MM #define INCL_OS2MM
#define INCL_MMIOOS2 #define INCL_MMIOOS2
...@@ -60,5 +61,6 @@ struct SDL_PrivateAudioData ...@@ -60,5 +61,6 @@ struct SDL_PrivateAudioData
HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -28,85 +28,11 @@ ...@@ -28,85 +28,11 @@
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dcaudio.h" #include "SDL_dcaudio.h"
#include "aica.h" #include "aica.h"
#include <dc/spu.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 #define SPU_RAM_BASE 0xa0800000
static void static void
...@@ -152,7 +78,7 @@ spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size) ...@@ -152,7 +78,7 @@ spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size)
} }
static void static void
DCAUD_PlayAudio(_THIS) DCAUD_PlayDevice(_THIS)
{ {
SDL_AudioSpec *spec = &this->spec; SDL_AudioSpec *spec = &this->spec;
unsigned int offset; unsigned int offset;
...@@ -200,28 +126,59 @@ DCAUD_PlayAudio(_THIS) ...@@ -200,28 +126,59 @@ DCAUD_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
DCAUD_GetAudioBuf(_THIS) DCAUD_GetDeviceBuf(_THIS)
{ {
return (this->hidden->mixbuf); return (this->hidden->mixbuf);
} }
/* This function waits until it is possible to write a full sound buffer */
static void static void
DCAUD_CloseAudio(_THIS) DCAUD_WaitDevice(_THIS)
{ {
aica_stop(0); if (this->hidden->playing) {
if (this->spec.channels == 2) /* wait */
aica_stop(1); while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
if (this->hidden->mixbuf != NULL) { thd_pass();
SDL_FreeAudioMem(this->hidden->mixbuf); }
this->hidden->mixbuf = NULL; }
}
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 static int
DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec) DCAUD_OpenDevice(_THIS, SDL_AudioSpec * spec)
{ {
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 0; 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)) { while ((!valid_datatype) && (test_format)) {
spec->format = test_format; spec->format = test_format;
switch (test_format) { switch (test_format) {
...@@ -238,8 +195,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -238,8 +195,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
if (!valid_datatype) { /* shouldn't happen, but just in case... */ if (!valid_datatype) { /* shouldn't happen, but just in case... */
DCAUD_CloseDevice(this);
SDL_SetError("Unsupported audio format"); SDL_SetError("Unsupported audio format");
return (-1); return 0;
} }
if (spec->channels > 2) if (spec->channels > 2)
...@@ -252,7 +210,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -252,7 +210,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
this->hidden->mixlen = spec->size; this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return (-1); DCAUD_CloseDevice(this);
SDL_OutOfMemory();
return 0;
} }
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
this->hidden->leftpos = 0x11000; this->hidden->leftpos = 0x11000;
...@@ -261,7 +221,25 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -261,7 +221,25 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
this->hidden->nextbuf = 0; this->hidden->nextbuf = 0;
/* We're ready to rock and roll. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_diskaudio.h" #include "SDL_diskaudio.h"
/* The tag name used by DISK audio */ /* The tag name used by DISK audio */
...@@ -46,90 +45,27 @@ ...@@ -46,90 +45,27 @@
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY" #define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150 #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 * static const char *
DISKAUD_GetOutputFilename(void) DISKAUD_GetOutputFilename(const char *devname)
{
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)
{ {
SDL_AudioDevice *this; if (devname == NULL) {
const char *envr; devname = SDL_getenv(DISKENVR_OUTFILE);
if (devname == NULL) {
/* Initialize all variables that we clean on shutdown */ devname = DISKDEFAULT_OUTFILE;
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)); return devname;
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;
} }
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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
DISKAUD_WaitAudio(_THIS) DISKAUD_WaitDevice(_THIS)
{ {
SDL_Delay(this->hidden->write_delay); SDL_Delay(this->hidden->write_delay);
} }
static void static void
DISKAUD_PlayAudio(_THIS) DISKAUD_PlayDevice(_THIS)
{ {
int written; int written;
...@@ -147,49 +83,86 @@ DISKAUD_PlayAudio(_THIS) ...@@ -147,49 +83,86 @@ DISKAUD_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
DISKAUD_GetAudioBuf(_THIS) DISKAUD_GetDeviceBuf(_THIS)
{ {
return (this->hidden->mixbuf); return (this->hidden->mixbuf);
} }
static void static void
DISKAUD_CloseAudio(_THIS) DISKAUD_CloseDevice(_THIS)
{ {
if (this->hidden->mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf); if (this->hidden->mixbuf != NULL) {
this->hidden->mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (this->hidden->output != NULL) { }
SDL_RWclose(this->hidden->output); if (this->hidden->output != NULL) {
this->hidden->output = NULL; SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int 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 */ /* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb"); this->hidden->output = SDL_RWFromFile(fname, "wb");
if (this->hidden->output == NULL) { 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 */ /* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) { 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. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "SDL_rwops.h" #include "SDL_rwops.h"
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
/* !!! FIXME: merge this driver with "dsp". */
/* Allow access to a raw mixing buffer */ /* Allow access to a raw mixing buffer */
#include <stdio.h> #include <stdio.h>
...@@ -57,208 +59,100 @@ ...@@ -57,208 +59,100 @@
#define DMA_DRIVER_NAME "dma" #define DMA_DRIVER_NAME "dma"
/* Open the audio device for playback, and don't block if busy */ /* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_RDWR|O_NONBLOCK) #define OPEN_FLAGS_INPUT (O_RDWR|O_NONBLOCK)
#define OPEN_FLAGS_OUTPUT (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);
/* Audio driver bootstrap functions */ static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
static int static int
Audio_Available(void) test_for_mmap(int fd)
{ {
int available; int caps = 0;
int fd; struct audio_buf_info info;
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
available = 0; (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0))
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); {
if (fd >= 0) { size_t len = info.fragstotal * info.fragsize;
int caps; Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
struct audio_buf_info info; if (buf != MAP_FAILED) {
munmap(buf, len);
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) && return 1;
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) {
available = 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_FreeUnixAudioDevices(devs, count);
SDL_free(device);
} }
static SDL_AudioDevice * static inline void
Audio_CreateDevice(int devindex) build_device_list(int iscapture, char ***devs, int *count)
{ {
SDL_AudioDevice *this; const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
/* Initialize all variables that we clean on shutdown */ SDL_EnumUnixAudioDevices(flags, 0, test_for_mmap, devs, count);
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;
} }
AudioBootStrap DMA_bootstrap = { static inline void
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", build_device_lists(void)
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
DMA_WaitAudio(_THIS)
{ {
fd_set fdset; build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
/* 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; static inline void
if (ticks > 0) { free_device_lists(void)
SDL_Delay(ticks); {
} free_device_list(&outputDevices, &outputDeviceCount);
} else { free_device_list(&inputDevices, &inputDeviceCount);
/* 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_PlayAudio(_THIS) static void DMA_Deinitialize(void)
{ {
/* If timer synchronization is enabled, set the next write frame */ free_device_lists();
if (frame_ticks) {
next_frame += frame_ticks;
}
return;
} }
static Uint8 * static int
DMA_GetAudioBuf(_THIS) DMA_DetectDevices(int iscapture)
{ {
count_info info; if (iscapture) {
int playing; build_device_list(1, &inputDevices, &inputDeviceCount);
int filling; return inputDeviceCount;
} else {
/* Get number of blocks, looping if we're not using select() */ build_device_list(0, &outputDevices, &outputDeviceCount);
do { return outputDeviceCount;
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; return 0; /* shouldn't ever hit this. */
filling = (playing + 1) % num_buffers;
return (dma_buf + (filling * this->spec.size));
} }
static void
DMA_CloseAudio(_THIS) static const char *
DMA_GetDeviceName(int index, int iscapture)
{ {
if (dma_buf != NULL) { if ((iscapture) && (index < inputDeviceCount)) {
munmap(dma_buf, dma_len); return inputDevices[index];
dma_buf = NULL; } else if ((!iscapture) && (index < outputDeviceCount)) {
} return outputDevices[index];
if (audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
} }
SDL_SetError("No such device");
return NULL;
} }
static int static int
DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo)
SDL_AudioSpec * spec)
{ {
int frag_spec; int frag_spec;
int value; int value;
...@@ -272,11 +166,11 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, ...@@ -272,11 +166,11 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
} }
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */ /* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != spec->size) { if ((0x01 << frag_spec) != this->spec.size) {
SDL_SetError("Fragment size must be a power of two"); SDL_SetError("Fragment size must be a power of two");
return (-1); return (-1);
} }
...@@ -295,7 +189,7 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, ...@@ -295,7 +189,7 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
} }
/* Set mono or stereo audio */ /* Set mono or stereo audio */
value = (spec->channels > 1); value = (this->spec.channels > 1);
if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
(value != stereo)) { (value != stereo)) {
SDL_SetError("Couldn't set audio channels"); SDL_SetError("Couldn't set audio channels");
...@@ -303,48 +197,86 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, ...@@ -303,48 +197,86 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
} }
/* Set the DSP frequency */ /* Set the DSP frequency */
value = spec->freq; value = this->spec.freq;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
SDL_SetError("Couldn't set audio frequency"); SDL_SetError("Couldn't set audio frequency");
return (-1); return (-1);
} }
spec->freq = value; this->spec.freq = value;
/* We successfully re-opened the audio */ /* We successfully re-opened the audio */
return (0); 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 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 format;
int stereo; int stereo;
int value; int value;
SDL_AudioFormat test_format; SDL_AudioFormat test_format;
struct audio_buf_info info; struct audio_buf_info info;
/* Reset the timer synchronization flag */ /* We don't care what the devname is...we'll try to open anything. */
frame_ticks = 0.0; /* ...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 */ /* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); audio_fd = open(devname, flags, 0);
if (audio_fd < 0) { if (audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); DMA_CloseDevice(this);
return (-1); SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
} }
dma_buf = NULL; dma_buf = NULL;
ioctl(audio_fd, SNDCTL_DSP_RESET, 0); ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
/* Get a list of supported hardware formats */ /* Get a list of supported hardware formats */
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't get audio format list"); SDL_SetError("Couldn't get audio format list");
return (-1); return 0;
} }
/* Try for a closest match on audio format */ /* Try for a closest match on audio format */
format = 0; format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format); for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) { !format && test_format;) {
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format); fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
...@@ -389,61 +321,66 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -389,61 +321,66 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
} }
if (format == 0) { if (format == 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats"); 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 */ /* Set the audio format */
value = format; value = format;
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't set audio format"); SDL_SetError("Couldn't set audio format");
return (-1); return 0;
} }
/* Set mono or stereo audio (currently only two channels supported) */ /* 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); ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
if (stereo) { if (stereo) {
spec->channels = 2; this->spec.channels = 2;
} else { } else {
spec->channels = 1; this->spec.channels = 1;
} }
/* Because some drivers don't allow setting the buffer size /* Because some drivers don't allow setting the buffer size
after setting the format, we must re-open the audio device after setting the format, we must re-open the audio device
once we know what format and channels are supported 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() */ /* Error is set by DMA_ReopenAudio() */
return (-1); return 0;
} }
/* Memory map the audio buffer */ /* Memory map the audio buffer */
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't get OSPACE parameters"); SDL_SetError("Couldn't get OSPACE parameters");
return (-1); return 0;
} }
spec->size = info.fragsize; this->spec.size = info.fragsize;
spec->samples = spec->size / ((spec->format & 0xFF) / 8); this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8);
spec->samples /= spec->channels; this->spec.samples /= this->spec.channels;
num_buffers = info.fragstotal; 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, dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
audio_fd, 0); audio_fd, 0);
if (dma_buf == MAP_FAILED) { if (dma_buf == MAP_FAILED) {
DMA_CloseDevice(this);
SDL_SetError("DMA memory map failed"); SDL_SetError("DMA memory map failed");
dma_buf = NULL; 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 */ /* Check to see if we need to use select() workaround */
{ {
char *workaround; char *workaround;
workaround = SDL_getenv("SDL_DSP_NOSELECT"); workaround = SDL_getenv("SDL_DSP_NOSELECT");
if (workaround) { 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; next_frame = SDL_GetTicks() + frame_ticks;
} }
} }
...@@ -453,15 +390,145 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -453,15 +390,145 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value); ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
value = PCM_ENABLE_OUTPUT; value = PCM_ENABLE_OUTPUT;
if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) {
DMA_CloseDevice(this);
SDL_SetError("Couldn't trigger audio output"); SDL_SetError("Couldn't trigger audio output");
return (-1); return 0;
} }
/* Get the parent process id (we're the parent of the audio thread) */ /* Get the parent process id (we're the parent of the audio thread) */
parent = getpid(); parent = getpid();
/* We're ready to rock and roll. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_dspaudio_h #ifndef _SDL_dmaaudio_h
#define _SDL_dspaudio_h #define _SDL_dmaaudio_h
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -49,6 +49,7 @@ struct SDL_PrivateAudioData ...@@ -49,6 +49,7 @@ struct SDL_PrivateAudioData
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */ /* Old variable names */
/* !!! FIXME: remove these. */
#define audio_fd (this->hidden->audio_fd) #define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent) #define parent (this->hidden->parent)
#define dma_buf (this->hidden->dma_buf) #define dma_buf (this->hidden->dma_buf)
...@@ -57,5 +58,6 @@ struct SDL_PrivateAudioData ...@@ -57,5 +58,6 @@ struct SDL_PrivateAudioData
#define frame_ticks (this->hidden->frame_ticks) #define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame) #define next_frame (this->hidden->next_frame)
#endif /* _SDL_dspaudio_h */ #endif /* _SDL_dmaaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -45,73 +45,12 @@ ...@@ -45,73 +45,12 @@
#define alSetWidth(x,y) ALsetwidth(x,y) #define alSetWidth(x,y) ALsetwidth(x,y)
#endif #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 void static
AL_WaitAudio(_THIS) IRIXAUDIO_WaitDevice(_THIS)
{ {
Sint32 timeleft; Sint32 timeleft;
timeleft = this->spec.samples - alGetFillable(audio_port); timeleft = this->spec.samples - alGetFillable(this->hidden->audio_port);
if (timeleft > 0) { if (timeleft > 0) {
timeleft /= (this->spec.freq / 1000); timeleft /= (this->spec.freq / 1000);
SDL_Delay((Uint32) timeleft); SDL_Delay((Uint32) timeleft);
...@@ -119,61 +58,78 @@ AL_WaitAudio(_THIS) ...@@ -119,61 +58,78 @@ AL_WaitAudio(_THIS)
} }
static void static void
AL_PlayAudio(_THIS) IRIXAUDIO_PlayDevice(_THIS)
{ {
/* Write the audio data out */ /* 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 */ /* Assume fatal error, for now */
this->enabled = 0; this->enabled = 0;
} }
} }
static Uint8 * static Uint8 *
AL_GetAudioBuf(_THIS) IRIXAUDIO_GetDeviceBuf(_THIS)
{ {
return (mixbuf); return (this->hidden->mixbuf);
} }
static void static void
AL_CloseAudio(_THIS) IRIXAUDIO_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_port != NULL) { }
alClosePort(audio_port); if (this->hidden->audio_port != NULL) {
audio_port = NULL; alClosePort(this->hidden->audio_port);
this->hidden->audio_port = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int 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 width = 0;
long fmt = 0; long fmt = 0;
int valid = 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 #ifdef OLD_IRIX_AUDIO
{ {
long audio_param[2]; long audio_param[2];
audio_param[0] = AL_OUTPUT_RATE; 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); valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
} }
#else #else
{ {
ALpv audio_param; ALpv audio_param;
audio_param.param = AL_RATE; 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); valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
} }
#endif #endif
while ((!valid) && (test_format)) { while ((!valid) && (test_format)) {
valid = 1; valid = 1;
spec->format = test_format; this->spec.format = test_format;
switch (test_format) { switch (test_format) {
case AUDIO_S8: case AUDIO_S8:
...@@ -203,30 +159,31 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -203,30 +159,31 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
ALconfig audio_config = alNewConfig(); ALconfig audio_config = alNewConfig();
valid = 0; valid = 0;
if (audio_config) { if (audio_config) {
if (alSetChannels(audio_config, spec->channels) < 0) { if (alSetChannels(audio_config, this->spec.channels) < 0) {
if (spec->channels > 2) { /* can't handle > stereo? */ if (this->spec.channels > 2) { /* can't handle > stereo? */
spec->channels = 2; /* try again below. */ this->spec.channels = 2; /* try again below. */
} }
} }
if ((alSetSampFmt(audio_config, fmt) >= 0) && if ((alSetSampFmt(audio_config, fmt) >= 0) &&
((!width) || (alSetWidth(audio_config, width) >= 0)) && ((!width) || (alSetWidth(audio_config, width) >= 0)) &&
(alSetQueueSize(audio_config, spec->samples * 2) >= 0) && (alSetQueueSize(audio_config,this->spec.samples*2) >= 0) &&
(alSetChannels(audio_config, spec->channels) >= 0)) { (alSetChannels(audio_config, this->spec.channels) >= 0)) {
audio_port = alOpenPort("SDL audio", "w", audio_config); this->hidden->audio_port = alOpenPort("SDL audio", "w",
if (audio_port == NULL) { audio_config);
if (this->hidden->audio_port == NULL) {
/* docs say AL_BAD_CHANNELS happens here, too. */ /* docs say AL_BAD_CHANNELS happens here, too. */
int err = oserror(); int err = oserror();
if (err == AL_BAD_CHANNELS) { if (err == AL_BAD_CHANNELS) {
spec->channels = 2; this->spec.channels = 2;
alSetChannels(audio_config, spec->channels); alSetChannels(audio_config, this->spec.channels);
audio_port = alOpenPort("SDL audio", "w", this->hidden->audio_port = alOpenPort("SDL audio", "w",
audio_config); audio_config);
} }
} }
if (audio_port != NULL) { if (this->hidden->audio_port != NULL) {
valid = 1; valid = 1;
} }
} }
...@@ -237,23 +194,43 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -237,23 +194,43 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
if (!valid) { if (!valid) {
IRIXAUDIO_CloseDevice(this);
SDL_SetError("Unsupported audio format"); SDL_SetError("Unsupported audio format");
return (-1); return 0;
} }
/* Update the fragment size as size in bytes */ /* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
IRIXAUDIO_CloseDevice(this);
SDL_OutOfMemory(); 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. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_irixaudio_h
#define _SDL_lowaudio_h #define _SDL_irixaudio_h
#include <dmedia/audio.h> #include <dmedia/audio.h>
...@@ -33,15 +33,10 @@ ...@@ -33,15 +33,10 @@
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
{ {
/* The handle for the audio device */ ALport audio_port; /* The handle for the audio device */
ALport audio_port; Uint8 *mixbuf; /* The app mixing buffer */
Uint8 *mixbuf; /* The app mixing buffer */
}; };
/* Old variable names */ #endif /* _SDL_irixaudio_h */
#define audio_port (this->hidden->audio_port)
#define mixbuf (this->hidden->mixbuf)
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -55,156 +55,158 @@ ...@@ -55,156 +55,158 @@
#define DSP_DRIVER_NAME "dsp" #define DSP_DRIVER_NAME "dsp"
/* Open the audio device for playback, and don't block if busy */ /* 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 char **outputDevices = NULL;
static int DSP_OpenAudio(_THIS, SDL_AudioSpec * spec); static int outputDeviceCount = 0;
static void DSP_WaitAudio(_THIS); static char **inputDevices = NULL;
static void DSP_PlayAudio(_THIS); static int inputDeviceCount = 0;
static Uint8 *DSP_GetAudioBuf(_THIS);
static void DSP_CloseAudio(_THIS);
/* Audio driver bootstrap functions */ static inline void
free_device_list(char ***devs, int *count)
static int
Audio_Available(void)
{ {
int fd; SDL_FreeUnixAudioDevices(devs, count);
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
available = 1;
close(fd);
}
return (available);
} }
static void static inline void
Audio_DeleteDevice(SDL_AudioDevice * device) build_device_list(int iscapture, char ***devs, int *count)
{ {
SDL_free(device->hidden); const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_free(device); free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
} }
static SDL_AudioDevice * static inline void
Audio_CreateDevice(int devindex) 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);
}
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;
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 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) { if (iscapture) {
perror("Audio write"); build_device_list(1, &inputDevices, &inputDeviceCount);
this->enabled = 0; return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
} }
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); return 0; /* shouldn't ever hit this. */
#endif
} }
static Uint8 * static const char *
DSP_GetAudioBuf(_THIS) 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 static void
DSP_CloseAudio(_THIS) DSP_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_fd >= 0) { }
close(audio_fd); if (this->hidden->audio_fd >= 0) {
audio_fd = -1; close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int 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 format;
int value; int value;
int frag_spec; int frag_spec;
SDL_AudioFormat test_format; 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 */ /* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); this->hidden->audio_fd = open(devname, flags, 0);
if (audio_fd < 0) { if (this->hidden->audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); DSP_CloseDevice(this);
return (-1); 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() */ /* Make the file descriptor use blocking writes with fcntl() */
{ {
long flags; long ctlflags;
flags = fcntl(audio_fd, F_GETFL); ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
flags &= ~O_NONBLOCK; ctlflags &= ~O_NONBLOCK;
if (fcntl(audio_fd, F_SETFL, flags) < 0) { if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio blocking mode"); SDL_SetError("Couldn't set audio blocking mode");
DSP_CloseAudio(this); return 0;
return (-1);
} }
} }
/* Get a list of supported hardware formats */ /* 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"); perror("SNDCTL_DSP_GETFMTS");
DSP_CloseDevice(this);
SDL_SetError("Couldn't get audio format list"); SDL_SetError("Couldn't get audio format list");
DSP_CloseAudio(this); return 0;
return (-1);
} }
/* Try for a closest match on audio format */ /* Try for a closest match on audio format */
format = 0; format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format); for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) { !format && test_format;) {
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format); fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
...@@ -255,50 +257,51 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -255,50 +257,51 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
} }
if (format == 0) { if (format == 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats"); SDL_SetError("Couldn't find any hardware audio formats");
DSP_CloseAudio(this); return 0;
return (-1);
} }
spec->format = test_format; this->spec.format = test_format;
/* Set the audio format */ /* Set the audio format */
value = 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"); perror("SNDCTL_DSP_SETFMT");
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio format"); SDL_SetError("Couldn't set audio format");
DSP_CloseAudio(this); return 0;
return (-1);
} }
/* Set the number of channels of output */ /* Set the number of channels of output */
value = spec->channels; value = this->spec.channels;
if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
perror("SNDCTL_DSP_CHANNELS"); perror("SNDCTL_DSP_CHANNELS");
DSP_CloseDevice(this);
SDL_SetError("Cannot set the number of channels"); SDL_SetError("Cannot set the number of channels");
DSP_CloseAudio(this); return 0;
return (-1);
} }
spec->channels = value; this->spec.channels = value;
/* Set the DSP frequency */ /* Set the DSP frequency */
value = spec->freq; value = this->spec.freq;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
perror("SNDCTL_DSP_SPEED"); perror("SNDCTL_DSP_SPEED");
DSP_CloseDevice(this);
SDL_SetError("Couldn't set audio frequency"); SDL_SetError("Couldn't set audio frequency");
DSP_CloseAudio(this); return 0;
return (-1);
} }
spec->freq = value; this->spec.freq = value;
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */ /* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec); for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != spec->size) { if ((0x01U << frag_spec) != this->spec.size) {
DSP_CloseDevice(this);
SDL_SetError("Fragment size must be a power of two"); SDL_SetError("Fragment size must be a power of two");
DSP_CloseAudio(this); return 0;
return (-1);
} }
frag_spec |= 0x00020000; /* two fragments, for low latency */ frag_spec |= 0x00020000; /* two fragments, for low latency */
...@@ -307,13 +310,13 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -307,13 +310,13 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
fprintf(stderr, "Requesting %d fragments of size %d\n", fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF)); (frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
#endif #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"); perror("SNDCTL_DSP_SETFRAGMENT");
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
{ {
audio_buf_info info; 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, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal); fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize); fprintf(stderr, "fragsize = %d\n", info.fragsize);
...@@ -322,19 +325,59 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -322,19 +325,59 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
#endif #endif
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
DSP_CloseAudio(this); DSP_CloseDevice(this);
return (-1); 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();
/* We're ready to rock and roll. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -34,22 +34,11 @@ struct SDL_PrivateAudioData ...@@ -34,22 +34,11 @@ struct SDL_PrivateAudioData
/* The file descriptor for the audio device */ /* The file descriptor for the audio device */
int audio_fd; int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */ /* Raw mixing buffer */
Uint8 *mixbuf; Uint8 *mixbuf;
int mixlen; int mixlen;
}; };
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #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 */ #endif /* _SDL_dspaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -25,141 +25,27 @@ ...@@ -25,141 +25,27 @@
/* Output audio to nowhere... */ /* Output audio to nowhere... */
#include "SDL_rwops.h"
#include "SDL_timer.h"
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dummyaudio.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 static int
DUMMYAUD_Available(void) DUMMYAUD_OpenDevice(_THIS, const char *devname, int iscapture)
{
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)
{ {
SDL_free(device->hidden); return 1; /* always succeeds. */
SDL_free(device);
} }
static SDL_AudioDevice * static int
DUMMYAUD_CreateDevice(int devindex) 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 */ /* Set the function pointers */
this->OpenAudio = DUMMYAUD_OpenAudio; impl->OpenDevice = DUMMYAUD_OpenDevice;
this->WaitAudio = DUMMYAUD_WaitAudio; impl->OnlyHasDefaultOutputDevice = 1;
this->PlayAudio = DUMMYAUD_PlayAudio; return 1;
this->GetAudioBuf = DUMMYAUD_GetAudioBuf;
this->CloseAudio = DUMMYAUD_CloseAudio;
this->free = DUMMYAUD_DeleteDevice;
return this;
} }
AudioBootStrap DUMMYAUD_bootstrap = { AudioBootStrap DUMMYAUD_bootstrap = {
DUMMYAUD_DRIVER_NAME, "SDL dummy audio driver", "dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
DUMMYAUD_Available, DUMMYAUD_CreateDevice
}; };
/* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_esdaudio.h" #include "SDL_esdaudio.h"
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
...@@ -46,40 +45,34 @@ ...@@ -46,40 +45,34 @@
/* The tag name used by ESD audio */ /* The tag name used by ESD audio */
#define ESD_DRIVER_NAME "esd" #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 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC; static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
static void *esd_handle = NULL; 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_open_sound)) (const char *host);
static int (*SDL_NAME(esd_close)) (int esd); static int (*SDL_NAME(esd_close)) (int esd);
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate, static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
const char *host, const char *name); const char *host, const char *name);
#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct static struct
{ {
const char *name; const char *name;
void **func; void **func;
} esd_functions[] = { } esd_functions[] = {
{ SDL_ESD_SYM(esd_open_sound),
"esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, { SDL_ESD_SYM(esd_close),
"esd_close", (void **) &SDL_NAME(esd_close)}, { SDL_ESD_SYM(esd_play_stream),
"esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},}; };
#undef SDL_ESD_SYM
static void static void
UnloadESDLibrary() UnloadESDLibrary()
{ {
if (esd_loaded) { if (esd_handle != NULL) {
SDL_UnloadObject(esd_handle); SDL_UnloadObject(esd_handle);
esd_handle = NULL; esd_handle = NULL;
esd_loaded = 0;
} }
} }
...@@ -88,17 +81,18 @@ LoadESDLibrary(void) ...@@ -88,17 +81,18 @@ LoadESDLibrary(void)
{ {
int i, retval = -1; int i, retval = -1;
esd_handle = SDL_LoadObject(esd_library); if (esd_handle == NULL) {
if (esd_handle) { esd_handle = SDL_LoadObject(esd_library);
esd_loaded = 1; if (esd_handle) {
retval = 0; retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) { for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func = *esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name); SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) { if (!*esd_functions[i].func) {
retval = -1; retval = -1;
UnloadESDLibrary(); UnloadESDLibrary();
break; break;
}
} }
} }
} }
...@@ -121,78 +115,10 @@ LoadESDLibrary(void) ...@@ -121,78 +115,10 @@ LoadESDLibrary(void)
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */ #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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
ESD_WaitAudio(_THIS) ESD_WaitDevice(_THIS)
{ {
Sint32 ticks; Sint32 ticks;
...@@ -202,28 +128,31 @@ ESD_WaitAudio(_THIS) ...@@ -202,28 +128,31 @@ ESD_WaitAudio(_THIS)
/* 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. that use a different process id for each thread.
*/ */
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ /* Check every 10 loops */
if (kill(parent, 0) < 0) { if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0; this->enabled = 0;
} }
} }
} }
/* Use timer for general audio synchronization */ /* 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) { if (ticks > 0) {
SDL_Delay(ticks); SDL_Delay(ticks);
} }
} }
static void static void
ESD_PlayAudio(_THIS) ESD_PlayDevice(_THIS)
{ {
int written; int written = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */ /* Write the audio data, checking for EAGAIN on broken audio drivers */
do { 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))) { if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */ SDL_Delay(1); /* Let a little CPU time go by */
} }
...@@ -232,7 +161,7 @@ ESD_PlayAudio(_THIS) ...@@ -232,7 +161,7 @@ ESD_PlayAudio(_THIS)
((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* Set the next write frame */ /* 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 we couldn't write, assume fatal error for now */
if (written < 0) { if (written < 0) {
...@@ -241,21 +170,26 @@ ESD_PlayAudio(_THIS) ...@@ -241,21 +170,26 @@ ESD_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
ESD_GetAudioBuf(_THIS) ESD_GetDeviceBuf(_THIS)
{ {
return (mixbuf); return (this->hidden->mixbuf);
} }
static void static void
ESD_CloseAudio(_THIS) ESD_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_fd >= 0) { }
SDL_NAME(esd_close) (audio_fd); if (this->hidden->audio_fd >= 0) {
audio_fd = -1; 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) ...@@ -285,59 +219,135 @@ get_progname(void)
return (progname); return (progname);
} }
static int 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 */ /* Convert audio spec to the ESD audio format */
format = (ESD_STREAM | ESD_PLAY); /* Try for a closest match on audio format */
switch (spec->format & 0xFF) { for (test_format = SDL_FirstAudioFormat(this->spec.format);
case 8: !found && test_format; test_format = SDL_NextAudioFormat()) {
format |= ESD_BITS8; #ifdef DEBUG_AUDIO
break; fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
case 16: #endif
format |= ESD_BITS16; found = 1;
break; switch (test_format) {
default: case AUDIO_U8:
SDL_SetError("Unsupported ESD audio format"); format |= ESD_BITS8;
return (-1); 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; format |= ESD_MONO;
} else { } else {
format |= ESD_STEREO; format |= ESD_STEREO;
} }
#if 0 #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 #endif
/* Open a connection to the ESD audio server */ /* Open a connection to the ESD audio server */
audio_fd = this->hidden->audio_fd =
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname()); SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname());
if (audio_fd < 0) {
if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't open ESD connection"); SDL_SetError("Couldn't open ESD connection");
return (-1); return 0;
} }
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
frame_ticks = (float) (spec->samples * 1000) / spec->freq; this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
next_frame = SDL_GetTicks() + frame_ticks; this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return (-1); 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) */ /* 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. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -47,13 +47,5 @@ struct SDL_PrivateAudioData ...@@ -47,13 +47,5 @@ struct SDL_PrivateAudioData
}; };
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #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 */ #endif /* _SDL_esdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
#include "SDL_audio.h" #include "SDL_audio.h"
...@@ -28,79 +29,233 @@ ...@@ -28,79 +29,233 @@
#include "../SDL_sysaudio.h" #include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h" #include "SDL_coreaudio.h"
#define DEBUG_COREAUDIO 0
/* Audio driver functions */ typedef struct COREAUDIO_DeviceList
{
static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec); AudioDeviceID id;
static void Core_WaitAudio(_THIS); const char *name;
static void Core_PlayAudio(_THIS); } COREAUDIO_DeviceList;
static Uint8 *Core_GetAudioBuf(_THIS);
static void Core_CloseAudio(_THIS);
/* Audio driver bootstrap functions */ static COREAUDIO_DeviceList *inputDevices = NULL;
static int inputDeviceCount = 0;
static COREAUDIO_DeviceList *outputDevices = NULL;
static int outputDeviceCount = 0;
static int static void
Audio_Available(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 static void
Audio_DeleteDevice(SDL_AudioDevice * device) build_device_list(int iscapture, COREAUDIO_DeviceList **devices, int *devCount)
{ {
SDL_free(device->hidden); Boolean outWritable = 0;
SDL_free(device); 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 * static inline void
Audio_CreateDevice(int devindex) 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)); static inline void
if (this) { free_device_lists(void)
SDL_memset(this, 0, (sizeof *this)); {
this->hidden = (struct SDL_PrivateAudioData *) free_device_list(&outputDevices, &outputDeviceCount);
SDL_malloc((sizeof *this->hidden)); free_device_list(&inputDevices, &inputDeviceCount);
} }
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) { static int
SDL_free(this); 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 */ return 0;
this->OpenAudio = Core_OpenAudio; }
this->WaitAudio = Core_WaitAudio;
this->PlayAudio = Core_PlayAudio;
this->GetAudioBuf = Core_GetAudioBuf; static int
this->CloseAudio = Core_CloseAudio; 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 */ /* The CoreAudio callback */
static OSStatus static OSStatus
audioCallback(void *inRefCon, outputCallback(void *inRefCon,
AudioUnitRenderActionFlags inActionFlags, AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp * inTimeStamp, const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, AudioBuffer * ioData) UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioDataList)
{ {
SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon; SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
AudioBuffer *ioData = &ioDataList->mBuffers[0];
UInt32 remaining, len; UInt32 remaining, len;
void *ptr; 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 */ /* Only do anything if audio is enabled and not paused */
if (!this->enabled || this->paused) { if (!this->enabled || this->paused) {
SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize); SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
...@@ -118,109 +273,251 @@ audioCallback(void *inRefCon, ...@@ -118,109 +273,251 @@ audioCallback(void *inRefCon,
remaining = ioData->mDataByteSize; remaining = ioData->mDataByteSize;
ptr = ioData->mData; ptr = ioData->mData;
while (remaining > 0) { while (remaining > 0) {
if (bufferOffset >= bufferSize) { if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */ /* 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); 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); SDL_mutexV(this->mixer_lock);
bufferOffset = 0; this->hidden->bufferOffset = 0;
} }
len = bufferSize - bufferOffset; len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining) if (len > remaining)
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; ptr = (char *) ptr + len;
remaining -= len; remaining -= len;
bufferOffset += len; this->hidden->bufferOffset += len;
} }
return 0; return 0;
} }
/* Dummy functions -- we don't use thread-based audio */ static OSStatus
void inputCallback(void *inRefCon,
Core_WaitAudio(_THIS) 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 * static void
Core_GetAudioBuf(_THIS) 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 */ #define CHECK_RESULT(msg) \
result = AudioOutputUnitStop(outputAudioUnit); if (result != noErr) { \
if (result != noErr) { COREAUDIO_CloseDevice(this); \
SDL_SetError("Core_CloseAudio: AudioOutputUnitStop"); SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
return; return 0; \
} }
/* Remove the input callback */ static int
callback.inputProc = 0; find_device_by_name(_THIS, const char *devname, int iscapture)
callback.inputProcRefCon = 0; {
result = AudioUnitSetProperty(outputAudioUnit, AudioDeviceID devid = 0;
kAudioUnitProperty_SetInputCallback, OSStatus result = noErr;
kAudioUnitScope_Input, UInt32 size = 0;
0, &callback, sizeof(callback)); UInt32 alive = 0;
if (result != noErr) { pid_t pid = 0;
SDL_SetError
("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)"); if (devname == NULL) {
return; 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); size = sizeof (alive);
if (result != noErr) { result = AudioDeviceGetProperty(devid, 0, iscapture,
SDL_SetError("Core_CloseAudio: CloseComponent"); kAudioDevicePropertyDeviceIsAlive,
return; &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) \ /* some devices don't support this property, so errors are fine here. */
if (result != noErr) { \ if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ SDL_SetError("CoreAudio: requested device is being hogged.");
return -1; \ return 0;
} }
this->hidden->deviceID = devid;
return 1;
}
int static int
Core_OpenAudio(_THIS, SDL_AudioSpec * spec) prepare_audiounit(_THIS, const char *devname, int iscapture,
const AudioStreamBasicDescription *strdesc)
{ {
OSStatus result = noErr; OSStatus result = noErr;
Component comp; AURenderCallbackStruct callback;
ComponentDescription desc; 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; AudioStreamBasicDescription strdesc;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0; 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 */ /* Setup a AudioStreamBasicDescription with the requested format */
memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription)); SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = spec->channels; strdesc.mChannelsPerFrame = this->spec.channels;
strdesc.mSampleRate = spec->freq; strdesc.mSampleRate = this->spec.freq;
strdesc.mFramesPerPacket = 1; strdesc.mFramesPerPacket = 1;
while ((!valid_datatype) && (test_format)) { 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. */ /* Just a list of valid SDL formats, so people don't pass junk here. */
switch (test_format) { switch (test_format) {
case AUDIO_U8: case AUDIO_U8:
...@@ -234,13 +531,13 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -234,13 +531,13 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
case AUDIO_F32LSB: case AUDIO_F32LSB:
case AUDIO_F32MSB: case AUDIO_F32MSB:
valid_datatype = 1; valid_datatype = 1;
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format); strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
if (SDL_AUDIO_ISBIGENDIAN(spec->format)) if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
if (SDL_AUDIO_ISFLOAT(spec->format)) if (SDL_AUDIO_ISFLOAT(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat; strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
else if (SDL_AUDIO_ISSIGNED(spec->format)) else if (SDL_AUDIO_ISSIGNED(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
break; break;
} }
...@@ -248,7 +545,7 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -248,7 +545,7 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
if (!valid_datatype) { /* shouldn't happen, but just in case... */ if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format"); SDL_SetError("Unsupported audio format");
return (-1); return 0;
} }
strdesc.mBytesPerFrame = strdesc.mBytesPerFrame =
...@@ -256,52 +553,31 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -256,52 +553,31 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
strdesc.mBytesPerPacket = strdesc.mBytesPerPacket =
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
/* Locate the default output audio unit */ if (!prepare_audiounit(this, devname, iscapture, &strdesc)) {
memset(&desc, '\0', sizeof(ComponentDescription)); return 0; /* prepare_audiounit() will call SDL_SetError()... */
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;
} }
/* Open & initialize the default output audio unit */ return 1; /* good to go. */
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);
/* Allocate a sample buffer */ static int
bufferOffset = bufferSize = this->spec.size; COREAUDIO_Init(SDL_AudioDriverImpl *impl)
buffer = SDL_malloc(bufferSize); {
/* 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 */ build_device_lists(); /* do an initial check for devices... */
result = AudioOutputUnitStart(outputAudioUnit);
CHECK_RESULT("AudioOutputUnitStart") return 1;
/* We're running! */
return (1);
} }
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "Mac OS X CoreAudio", COREAUDIO_Init, 0
};
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,22 +26,17 @@ ...@@ -26,22 +26,17 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
{ {
AudioUnit outputAudioUnit; AudioUnit audioUnit;
void *buffer; void *buffer;
UInt32 bufferOffset; UInt32 bufferOffset;
UInt32 bufferSize; 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 */ #endif /* _SDL_coreaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,11 +21,16 @@ ...@@ -21,11 +21,16 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
/* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
# define SDL_MACOS_NAME "Mac OS X"
# include <Carbon/Carbon.h> # include <Carbon/Carbon.h>
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335) #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
# define SDL_MACOS_NAME "Mac OS 9"
# include <Carbon.h> # include <Carbon.h>
#else #else
# define SDL_MACOS_NAME "Mac OS 9"
# include <Sound.h> /* SoundManager interface */ # include <Sound.h> /* SoundManager interface */
# include <Gestalt.h> # include <Gestalt.h>
# include <DriverServices.h> # include <DriverServices.h>
...@@ -45,72 +50,6 @@ ...@@ -45,72 +50,6 @@
#include "../SDL_sysaudio.h" #include "../SDL_sysaudio.h"
#include "SDL_romaudio.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 #pragma options align=power
static volatile SInt32 audio_is_locked = 0; static volatile SInt32 audio_is_locked = 0;
...@@ -121,6 +60,7 @@ static volatile UInt32 running = 0; ...@@ -121,6 +60,7 @@ static volatile UInt32 running = 0;
static CmpSoundHeader header; static CmpSoundHeader header;
static volatile Uint32 fill_me = 0; static volatile Uint32 fill_me = 0;
static void static void
mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer) mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
{ {
...@@ -150,13 +90,13 @@ mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer) ...@@ -150,13 +90,13 @@ mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
} }
static void static void
Mac_LockAudio(_THIS) SNDMGR_LockDevice(_THIS)
{ {
IncrementAtomic((SInt32 *) & audio_is_locked); IncrementAtomic((SInt32 *) & audio_is_locked);
} }
static void static void
Mac_UnlockAudio(_THIS) SNDMGR_UnlockDevice(_THIS)
{ {
SInt32 oldval; SInt32 oldval;
...@@ -198,7 +138,7 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed) ...@@ -198,7 +138,7 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
cmd.param2 = (long) &header; cmd.param2 = (long) &header;
SndDoCommand(chan, &cmd, 0); 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 * if audio device isn't locked, mix the next buffer to be queued in
...@@ -219,14 +159,25 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed) ...@@ -219,14 +159,25 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
} }
static int 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; SndCallBackUPP callback;
int sample_bits; int sample_bits;
int i; int i;
long initOptions; 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... */ /* Very few conversions are required, but... */
switch (spec->format) { switch (spec->format) {
case AUDIO_S8: case AUDIO_S8:
...@@ -242,10 +193,10 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -242,10 +193,10 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
spec->format = AUDIO_F32MSB; spec->format = AUDIO_F32MSB;
break; break;
} }
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* initialize bufferCmd header */ /* initialize bufferCmd header */
memset(&header, 0, sizeof(header)); SDL_memset(&header, 0, sizeof(header));
callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc); callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
sample_bits = spec->size / spec->samples / spec->channels * 8; sample_bits = spec->size / spec->samples / spec->channels * 8;
...@@ -278,20 +229,23 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -278,20 +229,23 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* allocate 2 buffers */ /* allocate 2 buffers */
for (i = 0; i < 2; i++) { 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) { if (buffer[i] == NULL) {
SNDMGR_CloseDevice(this);
SDL_OutOfMemory(); SDL_OutOfMemory();
return (-1); return 0;
} }
memset(buffer[i], 0, spec->size); SDL_memset(buffer[i], 0, spec->size);
} }
/* Create the sound manager channel */ /* Create the sound manager channel */
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel)); channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
if (channel == NULL) { if (channel == NULL) {
SNDMGR_CloseDevice(this);
SDL_OutOfMemory(); SDL_OutOfMemory();
return (-1); return 0;
} }
this->hidden->channel = channel;
if (spec->channels >= 2) { if (spec->channels >= 2) {
initOptions = initStereo; initOptions = initStereo;
} else { } else {
...@@ -300,10 +254,9 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -300,10 +254,9 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
channel->userInfo = (long) this; channel->userInfo = (long) this;
channel->qLength = 128; channel->qLength = 128;
if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) { if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
SNDMGR_CloseDevice(this);
SDL_SetError("Unable to create audio channel"); SDL_SetError("Unable to create audio channel");
SDL_free(channel); return 0;
channel = NULL;
return (-1);
} }
/* start playback */ /* start playback */
...@@ -319,16 +272,15 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -319,16 +272,15 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
} }
static void static void
Mac_CloseAudio(_THIS) SNDMGR_CloseDevice(_THIS)
{ {
int i; int i;
running = 0; running = 0;
if (channel) { if (this->hidden->channel) {
SndDisposeChannel(channel, true); SndDisposeChannel(this->hidden->channel, true);
channel = NULL; this->hidden->channel = NULL;
} }
for (i = 0; i < 2; ++i) { for (i = 0; i < 2; ++i) {
...@@ -337,193 +289,31 @@ Mac_CloseAudio(_THIS) ...@@ -337,193 +289,31 @@ Mac_CloseAudio(_THIS)
buffer[i] = NULL; buffer[i] = NULL;
} }
} }
} SDL_free(this->hidden);
this->hidden = 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;
} }
static int static int
DoubleBufferAudio_Available(void) SNDMGR_Init(SDL_AudioDriverImpl *impl)
{ {
int available; /* Set the function pointers */
NumVersion sndversion; impl->OpenDevice = SNDMGR_OpenDevice;
long response; impl->CloseDevice = SNDMGR_CloseDevice;
impl->ProvidesOwnCallbackThread = 1;
available = 0; impl->OnlyHasDefaultOutputDevice = 1;
sndversion = SndSoundManagerVersion();
if (sndversion.majorRev >= 3) { /* Mac OS X uses threaded audio, so normal thread code is okay */
if (Gestalt(gestaltSoundAttr, &response) == noErr) { #ifndef __MACOSX__
if ((response & (1 << gestaltSndPlayDoubleBuffer))) { impl->LockDevice = SNDMGR_LockDevice;
available = 1; impl->UnlockDevice = SNDMGR_UnlockDevice;
} impl->SkipMixerLock = 1;
} #endif
} 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);
}
return 1; 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,27 +26,14 @@ ...@@ -26,27 +26,14 @@
#include "../SDL_sysaudio.h" #include "../SDL_sysaudio.h"
/* This is Ryan's improved MacOS sound code, with locking support */ /* Hidden "this" pointer for the audio functions */
#define USE_RYANS_SOUNDCODE
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this #define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
{ {
/* Sound manager audio channel */ /* Sound manager audio channel */
SndChannelPtr 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 */ #endif /* _SDL_romaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -61,105 +61,8 @@ ...@@ -61,105 +61,8 @@
static unsigned long cookie_snd, cookie_mch; 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 static void
Audio_DeleteDevice(SDL_AudioDevice * device) MINTDMA8_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_DMA8_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
Audio_Available, Audio_CreateDevice
};
static void
Mint_LockAudio(_THIS)
{ {
void *oldpile; void *oldpile;
...@@ -170,7 +73,7 @@ Mint_LockAudio(_THIS) ...@@ -170,7 +73,7 @@ Mint_LockAudio(_THIS)
} }
static void static void
Mint_UnlockAudio(_THIS) MINTDMA8_UnlockDevice(_THIS)
{ {
void *oldpile; void *oldpile;
...@@ -181,57 +84,59 @@ Mint_UnlockAudio(_THIS) ...@@ -181,57 +84,59 @@ Mint_UnlockAudio(_THIS)
} }
static void static void
Mint_CloseAudio(_THIS) MINTDMA8_CloseDevice(_THIS)
{ {
void *oldpile; if (this->hidden != NULL) {
/* Stop replay */
void *oldpile = (void *) Super(0);
/* Stop replay */ DMAAUDIO_IO.control = 0;
oldpile = (void *) Super(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 */ /* Disable interrupt */
Jdisint(MFP_DMASOUND); Jdisint(MFP_DMASOUND);
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n")); DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
/* Wait if currently playing sound */ /* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) { 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 */ /* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) { if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]); Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; 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 static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) MINTDMA8_CheckAudio(_THIS)
{ {
int i, masterprediv, sfreq; int i, masterprediv, sfreq;
unsigned long masterclock; unsigned long masterclock;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (spec->channels > 2) { if (this->spec.channels > 2) {
spec->channels = 2; /* no more than stereo! */ this->spec.channels = 2; /* no more than stereo! */
} }
/* Check formats available */ /* Check formats available */
spec->format = AUDIO_S8; this->spec.format = AUDIO_S8;
/* Calculate and select the closest frequency */ /* Calculate and select the closest frequency */
sfreq = 0; sfreq = 0;
...@@ -272,22 +177,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -272,22 +177,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
} }
#endif #endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq); MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ", DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0; return 0;
} }
static void static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec) MINTDMA8_InitAudio(_THIS)
{ {
void *oldpile; void *oldpile;
unsigned long buffer; unsigned long buffer;
...@@ -316,7 +221,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -316,7 +221,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
DMAAUDIO_IO.end_low = buffer & 255; DMAAUDIO_IO.end_low = buffer & 255;
mode = 3 - MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; mode = 3 - MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if (spec->channels == 1) { if (this->spec.channels == 1) {
mode |= 1 << 7; mode |= 1 << 7;
} }
DMAAUDIO_IO.sound_ctrl = mode; DMAAUDIO_IO.sound_ctrl = mode;
...@@ -339,29 +244,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -339,29 +244,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
} }
static int static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) MINTDMA8_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
SDL_MintAudio_device = this; SDL_MintAudio_device = this;
/* Check audio capabilities */ /* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) { if (MINTDMA8_CheckAudio(this) == -1) {
return -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 */ /* 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) { if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); SDL_free(this->hidden);
return (-1); 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_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2); SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = spec->size; SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0; SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
...@@ -372,9 +288,56 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -372,9 +288,56 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu(); SDL_MintAudio_CheckFpu();
/* Setup audio hardware */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -63,176 +63,83 @@ static unsigned long cookie_snd, cookie_gsxb; ...@@ -63,176 +63,83 @@ static unsigned long cookie_snd, cookie_gsxb;
/*--- Audio driver functions ---*/ /*--- 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 */ /* GSXB callbacks */
static void Mint_GsxbInterrupt(void); static void MINTGSXB_GsxbInterrupt(void);
static void Mint_GsxbNullInterrupt(void); static void MINTGSXB_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 static void
Audio_DeleteDevice(SDL_AudioDevice * device) MINTGSXB_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_GSXB_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
Audio_Available, Audio_CreateDevice
};
static void
Mint_LockAudio(_THIS)
{ {
/* Stop replay */ /* Stop replay */
Buffoper(0); Buffoper(0);
} }
static void static void
Mint_UnlockAudio(_THIS) MINTGSXB_UnlockDevice(_THIS)
{ {
/* Restart replay */ /* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT); Buffoper(SB_PLA_ENA | SB_PLA_RPT);
} }
static void static void
Mint_CloseAudio(_THIS) MINTGSXB_CloseDevice(_THIS)
{ {
/* Stop replay */ if (this->hidden != NULL) {
Buffoper(0); /* Stop replay */
Buffoper(0);
/* Uninstall interrupt */ /* Uninstall interrupt */
if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt) < 0) { if (NSetinterrupt(2, SI_NONE, MINTGSXB_GsxbNullInterrupt) < 0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n")); DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
} }
/* Wait if currently playing sound */ /* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) { while (SDL_MintAudio_mutex != 0) {}
}
/* Clear buffers */ /* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) { if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]); Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
} }
/* Unlock sound system */ /* Unlock sound system */
Unlocksnd(); Unlocksnd();
SDL_free(this->hidden);
this->hidden = NULL;
}
} }
static int static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) MINTGSXB_CheckAudio(_THIS)
{ {
long snd_format; long snd_format;
int i, resolution, format_signed, format_bigendian; 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; int valid_datatype = 0;
resolution = SDL_AUDIO_BITSIZE(spec->format); resolution = SDL_AUDIO_BITSIZE(this->spec.format);
format_signed = SDL_AUDIO_ISSIGNED(spec->format); format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format); format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", resolution)); 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(("signed=%d, ", format_signed));
DEBUG_PRINT(("big endian=%d, ", format_bigendian)); DEBUG_PRINT(("big endian=%d, ", format_bigendian));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (spec->channels > 2) { if (this->spec.channels > 2) {
spec->channels = 2; /* no more than stereo! */ this->spec.channels = 2; /* no more than stereo! */
} }
while ((!valid_datatype) && (test_format)) { while ((!valid_datatype) && (test_format)) {
/* Check formats available */ /* Check formats available */
snd_format = Sndstatus(SND_QUERYFORMATS); snd_format = Sndstatus(SND_QUERYFORMATS);
spec->format = test_format; this->spec.format = test_format;
resolution = SDL_AUDIO_BITSIZE(spec->format); resolution = SDL_AUDIO_BITSIZE(this->spec.format);
format_signed = SDL_AUDIO_ISSIGNED(spec->format); format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format); format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
switch (test_format) { switch (test_format) {
case AUDIO_U8: case AUDIO_U8:
case AUDIO_S8: case AUDIO_S8:
...@@ -279,14 +186,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -279,14 +186,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
/* Ok */ /* Ok */
} else if (snd_format & SND_FORMATUNSIGNED) { } else if (snd_format & SND_FORMATUNSIGNED) {
/* Give unsigned format */ /* Give unsigned format */
spec->format = spec->format & (~SDL_AUDIO_MASK_SIGNED); this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_SIGNED);
} }
} else { } else {
if (snd_format & SND_FORMATUNSIGNED) { if (snd_format & SND_FORMATUNSIGNED) {
/* Ok */ /* Ok */
} else if (snd_format & SND_FORMATSIGNED) { } else if (snd_format & SND_FORMATSIGNED) {
/* Give signed format */ /* 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) ...@@ -295,14 +202,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
/* Ok */ /* Ok */
} else if (snd_format & SND_FORMATLITTLEENDIAN) { } else if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Give little endian format */ /* Give little endian format */
spec->format = spec->format & (~SDL_AUDIO_MASK_ENDIAN); this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_ENDIAN);
} }
} else { } else {
if (snd_format & SND_FORMATLITTLEENDIAN) { if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Ok */ /* Ok */
} else if (snd_format & SND_FORMATBIGENDIAN) { } else if (snd_format & SND_FORMATBIGENDIAN) {
/* Give big endian format */ /* 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) ...@@ -324,22 +231,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
} }
#endif #endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq); MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ", DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0; return 0;
} }
static void static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec) MINTGSXB_InitAudio(_THIS)
{ {
int channels_mode, prediv; int channels_mode, prediv;
void *buffer; void *buffer;
...@@ -352,23 +259,23 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -352,23 +259,23 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
Setmontracks(0); Setmontracks(0);
/* Select replay format */ /* Select replay format */
switch (SDL_AUDIO_BITSIZE(spec->format)) { switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: case 8:
if (spec->channels == 2) { if (this->spec.channels == 2) {
channels_mode = STEREO8; channels_mode = STEREO8;
} else { } else {
channels_mode = MONO8; channels_mode = MONO8;
} }
break; break;
case 16: case 16:
if (spec->channels == 2) { if (this->spec.channels == 2) {
channels_mode = STEREO16; channels_mode = STEREO16;
} else { } else {
channels_mode = MONO16; channels_mode = MONO16;
} }
break; break;
case 32: case 32:
if (spec->channels == 2) { if (this->spec.channels == 2) {
channels_mode = STEREO32; channels_mode = STEREO32;
} else { } else {
channels_mode = MONO32; channels_mode = MONO32;
...@@ -387,12 +294,12 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -387,12 +294,12 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */ /* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 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")); DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
} }
/* Install interrupt */ /* 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")); DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
} }
...@@ -402,35 +309,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -402,35 +309,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
} }
static int static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) MINTGSXB_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
/* Lock sound system */ /* Lock sound system */
if (Locksnd() != 1) { if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use"); SDL_SetError("MINTGSXB_OpenDevice: Audio system already in use");
return (-1); return 0;
} }
SDL_MintAudio_device = this; SDL_MintAudio_device = this;
/* Check audio capabilities */ /* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) { if (MINTGSXB_CheckAudio(this) == -1) {
return -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 */ /* 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) { if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); SDL_free(this->hidden);
return (-1); 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_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2); SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = spec->size; SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0; SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
...@@ -441,13 +359,13 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -441,13 +359,13 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu(); SDL_MintAudio_CheckFpu();
/* Setup audio hardware */ /* 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 static void
Mint_GsxbInterrupt(void) MINTGSXB_GsxbInterrupt(void)
{ {
Uint8 *newbuf; Uint8 *newbuf;
...@@ -465,8 +383,57 @@ Mint_GsxbInterrupt(void) ...@@ -465,8 +383,57 @@ Mint_GsxbInterrupt(void)
} }
static 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -61,192 +61,82 @@ ...@@ -61,192 +61,82 @@
/*--- Static variables ---*/ /*--- Static variables ---*/
static unsigned long cookie_snd, cookie_mch; static unsigned long cookie_snd = 0;
static cookie_mcsn_t *cookie_mcsn; static unsigned long cookie_mch = 0;
static cookie_mcsn_t *cookie_mcsn = NULL;
/*--- 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 void static void
Mint_LockAudio(_THIS) MINTMCSN_LockDevice(_THIS)
{ {
/* Stop replay */ /* Stop replay */
Buffoper(0); Buffoper(0);
} }
static void static void
Mint_UnlockAudio(_THIS) MINTMCSN_UnlockDevice(_THIS)
{ {
/* Restart replay */ /* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT); Buffoper(SB_PLA_ENA | SB_PLA_RPT);
} }
static void static void
Mint_CloseAudio(_THIS) MINTMCSN_CloseDevice(_THIS)
{ {
/* Stop replay */ if (this->hidden != NULL) {
SDL_MintAudio_WaitThread(); /* Stop replay */
Buffoper(0); SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
if (!SDL_MintAudio_mint_present) { /* Wait if currently playing sound */
/* Uninstall interrupt */ while (SDL_MintAudio_mutex != 0) {}
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */ /* Clear buffers */
while (SDL_MintAudio_mutex != 0) { if (SDL_MintAudio_audiobuf[0]) {
} Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */ /* Unlock sound system */
if (SDL_MintAudio_audiobuf[0]) { Unlocksnd();
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */ SDL_free(this->hidden);
Unlocksnd(); this->hidden = NULL;
}
} }
static int static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) MINTMCSN_CheckAudio(_THIS)
{ {
int i; int i;
unsigned long masterclock, masterprediv; unsigned long masterclock, masterprediv;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (spec->channels > 2) { if (this->spec.channels > 2) {
spec->channels = 2; /* no more than stereo! */ this->spec.channels = 2; /* no more than stereo! */
} }
/* Check formats available */ /* Check formats available */
MINTAUDIO_freqcount = 0; MINTAUDIO_freqcount = 0;
switch (cookie_mcsn->play) { switch (cookie_mcsn->play) {
case MCSN_ST: case MCSN_ST:
spec->channels = 1; this->spec.channels = 1;
spec->format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */ this->spec.format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */
SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1); SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1);
break; break;
case MCSN_TT: /* Also STE, Mega STE */ case MCSN_TT: /* Also STE, Mega STE */
spec->format = AUDIO_S8; this->spec.format = AUDIO_S8;
masterclock = MASTERCLOCK_STE; masterclock = MASTERCLOCK_STE;
masterprediv = MASTERPREDIV_STE; masterprediv = MASTERPREDIV_STE;
if ((cookie_mch >> 16) == MCH_TT) { if ((cookie_mch >> 16) == MCH_TT) {
...@@ -280,10 +170,10 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -280,10 +170,10 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
(1 << i) - 1, -1); (1 << i) - 1, -1);
} }
} }
spec->format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */ this->spec.format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
if ((SDL_AUDIO_BITSIZE(spec->format)) == 16) { if ((SDL_AUDIO_BITSIZE(this->spec.format)) == 16) {
spec->format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */ this->spec.format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */
spec->channels = 2; /* 16 bits always stereo */ this->spec.channels = 2; /* 16 bits always stereo */
} }
break; break;
} }
...@@ -297,22 +187,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -297,22 +187,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
} }
#endif #endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq); MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ", DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0; return 0;
} }
static void static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec) MINTMCSN_InitAudio(_THIS)
{ {
int channels_mode, prediv, dmaclock; int channels_mode, prediv, dmaclock;
void *buffer; void *buffer;
...@@ -329,9 +219,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -329,9 +219,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */ /* Select replay format */
channels_mode = STEREO16; channels_mode = STEREO16;
switch (SDL_AUDIO_BITSIZE(spec->format)) { switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: case 8:
if (spec->channels == 2) { if (this->spec.channels == 2) {
channels_mode = STEREO8; channels_mode = STEREO8;
} else { } else {
channels_mode = MONO8; channels_mode = MONO8;
...@@ -358,7 +248,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -358,7 +248,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */ /* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 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")); DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
} }
...@@ -381,35 +271,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -381,35 +271,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
} }
static int static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) MINTMCSN_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
/* Lock sound system */ /* Lock sound system */
if (Locksnd() != 1) { if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use"); SDL_SetError("MINTMCSN_OpenDevice: Audio system already in use");
return (-1); return 0;
} }
SDL_MintAudio_device = this; SDL_MintAudio_device = this;
/* Check audio capabilities */ /* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) { if (MINTMCSN_CheckAudio(this) == -1) {
return -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 */ /* 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) { if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); SDL_free(this->hidden);
return (-1); 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_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2); SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = spec->size; SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0; SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
...@@ -420,9 +321,75 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -420,9 +321,75 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu(); SDL_MintAudio_CheckFpu();
/* Setup audio hardware */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -59,8 +59,9 @@ ...@@ -59,8 +59,9 @@
/*--- Static variables ---*/ /*--- Static variables ---*/
static unsigned long cookie_snd, cookie_mch; static unsigned long cookie_snd = 0;
static cookie_stfa_t *cookie_stfa; static unsigned long cookie_mch = 0;
static cookie_stfa_t *cookie_stfa = NULL;
static const int freqs[16] = { static const int freqs[16] = {
4995, 6269, 7493, 8192, 4995, 6269, 7493, 8192,
...@@ -69,157 +70,66 @@ static const int freqs[16] = { ...@@ -69,157 +70,66 @@ static const int freqs[16] = {
30720, 32336, 43885, 49152 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 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 */ /* Stop replay */
oldpile = (void *) Super(0); void *oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_DISABLE; cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
Super(oldpile); Super(oldpile);
} }
static void static void
Mint_UnlockAudio(_THIS) MINTSTFA_UnlockDevice(_THIS)
{ {
void *oldpile;
/* Restart replay */ /* Restart replay */
oldpile = (void *) Super(0); void *oldpile = (void *) Super(0);
cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT; cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT;
Super(oldpile); Super(oldpile);
} }
static void static void
Mint_CloseAudio(_THIS) MINTSTFA_CloseDevice(_THIS)
{ {
void *oldpile; if (this->hidden != NULL) {
/* Stop replay */
/* Stop replay */ void *oldpile = (void *) Super(0);
oldpile = (void *) Super(0); cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
cookie_stfa->sound_enable = STFA_PLAY_DISABLE; Super(oldpile);
Super(oldpile);
/* Wait if currently playing sound */
/* Wait if currently playing sound */ while (SDL_MintAudio_mutex != 0) {}
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 */ SDL_free(this->hidden);
if (SDL_MintAudio_audiobuf[0]) { this->hidden = NULL;
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
} }
} }
static int static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) MINTSTFA_CheckAudio(_THIS)
{ {
int i; int i;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
if (SDL_AUDIO_BITSIZE(spec->format) > 16) { if (SDL_AUDIO_BITSIZE(this->spec.format) > 16) {
spec->format = AUDIO_S16SYS; /* clamp out int32/float32 ... */ this->spec.format = AUDIO_S16SYS; /* clamp out int32/float32 ... */
} }
if (spec->channels > 2) { if (this->spec.channels > 2) {
spec->channels = 2; /* no more than stereo! */ this->spec.channels = 2; /* no more than stereo! */
} }
/* Check formats available */ /* Check formats available */
...@@ -237,29 +147,25 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -237,29 +147,25 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
} }
#endif #endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq); MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ", DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0; return 0;
} }
static void static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec) MINTSTFA_InitAudio(_THIS)
{ {
void *buffer; void *buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
void *oldpile; void *oldpile = (void *) Super(0);
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
oldpile = (void *) Super(0);
/* Stop replay */ /* Stop replay */
cookie_stfa->sound_enable = STFA_PLAY_DISABLE; cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
...@@ -267,22 +173,22 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -267,22 +173,22 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */ /* Select replay format */
cookie_stfa->sound_control = cookie_stfa->sound_control =
MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; 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; cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
} else { } else {
cookie_stfa->sound_control |= STFA_FORMAT_16BIT; cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
} }
if (spec->channels == 2) { if (this->spec.channels == 2) {
cookie_stfa->sound_control |= STFA_FORMAT_STEREO; cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
} else { } else {
cookie_stfa->sound_control |= STFA_FORMAT_MONO; 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; cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
} else { } else {
cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED; 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; cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
} else { } else {
cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN; cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
...@@ -290,7 +196,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -290,7 +196,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */ /* Set buffer */
cookie_stfa->sound_start = (unsigned long) 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 */ /* Set interrupt */
cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt; cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
...@@ -304,29 +210,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -304,29 +210,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
} }
static int static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) MINTSTFA_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
SDL_MintAudio_device = this; SDL_MintAudio_device = this;
/* Check audio capabilities */ /* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) { if (MINTSTFA_CheckAudio(this) == -1) {
return -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 */ /* 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) { if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); SDL_OutOfMemory()
return (-1); 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_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2); SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = spec->size; SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0; SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
...@@ -337,9 +254,49 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -337,9 +254,49 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu(); SDL_MintAudio_CheckFpu();
/* Setup audio hardware */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -60,147 +60,50 @@ ...@@ -60,147 +60,50 @@
#define DEBUG_PRINT(what) #define DEBUG_PRINT(what)
#endif #endif
/*--- Static variables ---*/ static unsigned long cookie_snd = 0;
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 void static void
Mint_LockAudio(_THIS) MINTXBIOS_LockDevice(_THIS)
{ {
/* Stop replay */ /* Stop replay */
Buffoper(0); Buffoper(0);
} }
static void static void
Mint_UnlockAudio(_THIS) MINTXBIOS_UnlockDevice(_THIS)
{ {
/* Restart replay */ /* Restart replay */
Buffoper(SB_PLA_ENA | SB_PLA_RPT); Buffoper(SB_PLA_ENA | SB_PLA_RPT);
} }
static void static void
Mint_CloseAudio(_THIS) MINTXBIOS_CloseDevice(_THIS)
{ {
/* Stop replay */ if (this->hidden != NULL) {
SDL_MintAudio_WaitThread(); /* Stop replay */
Buffoper(0); SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
if (!SDL_MintAudio_mint_present) { /* Wait if currently playing sound */
/* Uninstall interrupt */ while (SDL_MintAudio_mutex != 0) {}
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */ /* Clear buffers */
while (SDL_MintAudio_mutex != 0) { if (SDL_MintAudio_audiobuf[0]) {
} Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Clear buffers */ /* Unlock sound system */
if (SDL_MintAudio_audiobuf[0]) { Unlocksnd();
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */ SDL_free(this->hidden);
Unlocksnd(); this->hidden = NULL;
}
} }
/* Falcon XBIOS implementation of Devconnect() is buggy with external clock */ /* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
...@@ -269,7 +172,7 @@ Devconnect2(int src, int dst, int sclk, int pre) ...@@ -269,7 +172,7 @@ Devconnect2(int src, int dst, int sclk, int pre)
} }
static void static void
Mint_CheckExternalClock(_THIS) MINTXBIOS_CheckExternalClock(_THIS)
{ {
#define SIZE_BUF_CLOCK_MEASURE (44100/10) #define SIZE_BUF_CLOCK_MEASURE (44100/10)
...@@ -355,33 +258,33 @@ Mint_CheckExternalClock(_THIS) ...@@ -355,33 +258,33 @@ Mint_CheckExternalClock(_THIS)
} }
static int static int
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) MINTXBIOS_CheckAudio(_THIS)
{ {
int i; int i;
Uint32 extclock; Uint32 extclock;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); 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 */ /* clamp out int32/float32 */
if (SDL_AUDIO_BITSIZE(spec->format) >= 16) { if (SDL_AUDIO_BITSIZE(this->spec.format) >= 16) {
spec->format = AUDIO_S16MSB; /* Audio is always big endian */ this->spec.format = AUDIO_S16MSB; /* Audio is always big endian */
spec->channels = 2; /* 16 bits always stereo */ this->spec.channels = 2; /* 16 bits always stereo */
} else if (spec->channels > 2) { } else if (this->spec.channels > 2) {
spec->channels = 2; /* no more than stereo! */ this->spec.channels = 2; /* no more than stereo! */
} }
MINTAUDIO_freqcount = 0; MINTAUDIO_freqcount = 0;
/* Add external clocks if present */ /* Add external clocks if present */
Mint_CheckExternalClock(this); MINTXBIOS_CheckExternalClock(this);
/* Standard clocks */ /* Standard clocks */
for (i = 1; i < 12; i++) { for (i = 1; i < 12; i++) {
...@@ -404,22 +307,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec) ...@@ -404,22 +307,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
} }
#endif #endif
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq); MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ", DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
SDL_AUDIO_BITSIZE(spec->format))); SDL_AUDIO_BITSIZE(this->spec.format)));
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format))); DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format))); DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format))); DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
DEBUG_PRINT(("channels=%d, ", spec->channels)); DEBUG_PRINT(("channels=%d, ", this->spec.channels));
DEBUG_PRINT(("freq=%d\n", spec->freq)); DEBUG_PRINT(("freq=%d\n", this->spec.freq));
return 0; return 0;
} }
static void static void
Mint_InitAudio(_THIS, SDL_AudioSpec * spec) MINTXBIOS_InitAudio(_THIS)
{ {
int channels_mode, dmaclock, prediv; int channels_mode, dmaclock, prediv;
void *buffer; void *buffer;
...@@ -436,9 +339,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -436,9 +339,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Select replay format */ /* Select replay format */
channels_mode = STEREO16; channels_mode = STEREO16;
switch (SDL_AUDIO_BITSIZE(spec->format)) { switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: case 8:
if (spec->channels == 2) { if (this->spec.channels == 2) {
channels_mode = STEREO8; channels_mode = STEREO8;
} else { } else {
channels_mode = MONO8; channels_mode = MONO8;
...@@ -461,7 +364,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -461,7 +364,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
/* Set buffer */ /* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; 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")); DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
} }
...@@ -485,35 +388,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec) ...@@ -485,35 +388,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
} }
static int static int
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) MINTXBIOS_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
/* Lock sound system */ /* Lock sound system */
if (Locksnd() != 1) { if (Locksnd() != 1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use"); SDL_SetError("MINTXBIOS_OpenAudio: Audio system already in use");
return (-1); return 0;
} }
SDL_MintAudio_device = this; SDL_MintAudio_device = this;
/* Check audio capabilities */ /* Check audio capabilities */
if (Mint_CheckAudio(this, spec) == -1) { if (MINTXBIOS_CheckAudio(this) == -1) {
return -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 */ /* 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) { if (SDL_MintAudio_audiobuf[0] == NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); SDL_free(this->hidden);
return (-1); 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_MintAudio_numbuf = 0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2); SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
SDL_MintAudio_audiosize = spec->size; SDL_MintAudio_audiosize = this->spec.size;
SDL_MintAudio_mutex = 0; SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
...@@ -524,9 +438,58 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -524,9 +438,58 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
SDL_MintAudio_CheckFpu(); SDL_MintAudio_CheckFpu();
/* Setup audio hardware */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -31,70 +31,6 @@ ...@@ -31,70 +31,6 @@
static BOOL inUse[NUM_BUFFERS]; 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 static void
SetMMerror(char *function, MMRESULT code) SetMMerror(char *function, MMRESULT code)
{ {
...@@ -108,7 +44,7 @@ SetMMerror(char *function, MMRESULT code) ...@@ -108,7 +44,7 @@ SetMMerror(char *function, MMRESULT code)
} }
static void CALLBACK static void CALLBACK
MME_CALLBACK(HWAVEOUT hwo, MME_Callback(HWAVEOUT hwo,
UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2) UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2)
{ {
WAVEHDR *wp = (WAVEHDR *) dwParam1; WAVEHDR *wp = (WAVEHDR *) dwParam1;
...@@ -118,116 +54,137 @@ MME_CALLBACK(HWAVEOUT hwo, ...@@ -118,116 +54,137 @@ MME_CALLBACK(HWAVEOUT hwo,
} }
static int static int
MME_OpenAudio(_THIS, SDL_AudioSpec * spec) MME_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
int valid_format = 0;
MMRESULT result; MMRESULT result;
Uint8 *mixbuf = NULL;
int i; 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 */ /* Set basic WAVE format parameters */
shm = mmeAllocMem(sizeof(*shm)); this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
if (shm == NULL) { if (this->hidden->shm == NULL) {
SDL_SetError("Out of memory: shm"); MME_CloseDevice(this);
return (-1); 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 */ /* Determine the audio parameters from the AudioSpec */
switch (SDL_AUDIO_BITSIZE(spec->format)) { /* Try for a closest match on audio format */
case 8: for (test_format = SDL_FirstAudioFormat(this->spec.format);
/* Unsigned 8 bit audio data */ !valid_format && test_format;) {
spec->format = AUDIO_U8; valid_format = 1;
shm->wFmt.wBitsPerSample = 8; switch (test_format) {
break; case AUDIO_U8:
case 16: case AUDIO_S16:
/* Signed 16 bit audio data */ case AUDIO_S32:
spec->format = AUDIO_S16; break;
shm->wFmt.wBitsPerSample = 16; default:
break; valid_format = 0;
case 32: test_format = SDL_NextAudioFormat();
/* Signed 32 bit audio data */ }
spec->format = AUDIO_S32; }
shm->wFmt.wBitsPerSample = 32;
break; if (!valid_format) {
default: MME_CloseDevice(this);
SDL_SetError("Unsupported audio format"); 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? */ /* !!! FIXME: Can this handle more than stereo? */
shm->wFmt.wf.nChannels = spec->channels; this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
shm->wFmt.wf.nSamplesPerSec = spec->freq; this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
shm->wFmt.wf.nBlockAlign = this->hidden->shm->wFmt.wf.nBlockAlign =
shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8; this->hidden->shm->wFmt.wf.nChannels *
shm->wFmt.wf.nAvgBytesPerSec = this->hidden->shm->wFmt.wBitsPerSample / 8;
shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign; 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) */ /* Check the buffer size -- minimum of 1/4 second (word aligned) */
if (spec->samples < (spec->freq / 4)) if (this->spec.samples < (this->spec.freq / 4))
spec->samples = ((spec->freq / 4) + 3) & ~3; this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
/* Update the fragment size as size in bytes */ /* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */ /* Open the audio device */
result = waveOutOpen(&(shm->sound), result = waveOutOpen(&(this->hidden->shm->sound),
WAVE_MAPPER, WAVE_MAPPER,
&(shm->wFmt.wf), &(this->hidden->shm->wFmt.wf),
MME_CALLBACK, MME_Callback,
NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE)); NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR) {
MME_CloseDevice(this);
SetMMerror("waveOutOpen()", result); SetMMerror("waveOutOpen()", result);
return (-1); return 0;
} }
/* Create the sound buffers */ /* Create the sound buffers */
mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (spec->size)); mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
if (mixbuf == NULL) { if (mixbuf == NULL) {
SDL_SetError("Out of memory: mixbuf"); MME_CloseDevice(this);
return (-1); SDL_OutOfMemory();
return 0;
} }
this->hidden->mixbuf = mixbuf;
for (i = 0; i < NUM_BUFFERS; i++) { for (i = 0; i < NUM_BUFFERS; i++) {
shm->wHdr[i].lpData = &mixbuf[i * (spec->size)]; this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
shm->wHdr[i].dwBufferLength = spec->size; this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
shm->wHdr[i].dwFlags = 0; this->hidden->shm->wHdr[i].dwFlags = 0;
shm->wHdr[i].dwUser = i; this->hidden->shm->wHdr[i].dwUser = i;
shm->wHdr[i].dwLoops = 0; /* loop control counter */ this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
shm->wHdr[i].lpNext = NULL; /* reserved for driver */ this->hidden->shm->wHdr[i].lpNext = NULL; /* reserved for driver */
shm->wHdr[i].reserved = 0; this->hidden->shm->wHdr[i].reserved = 0;
inUse[i] = FALSE; inUse[i] = FALSE;
} }
next_buffer = 0; this->hidden->next_buffer = 0;
return 0;
return 1;
} }
static void static void
MME_WaitAudio(_THIS) MME_WaitDevice(_THIS)
{ {
while (inUse[next_buffer]) { while (inUse[this->hidden->next_buffer]) {
mmeWaitForCallbacks(); mmeWaitForCallbacks();
mmeProcessCallbacks(); mmeProcessCallbacks();
} }
} }
static Uint8 * static Uint8 *
MME_GetAudioBuf(_THIS) MME_GetDeviceBuf(_THIS)
{ {
Uint8 *retval; void *retval = this->hidden->shm->wHdr[this->hidden->next_buffer].lpData;
inUse[this->hidden->next_buffer] = TRUE;
inUse[next_buffer] = TRUE; return (Uint8 *) retval;
retval = (Uint8 *) (shm->wHdr[next_buffer].lpData);
return retval;
} }
static void static void
MME_PlayAudio(_THIS) MME_PlayDevice(_THIS)
{ {
/* Queue it up */ /* Queue it up */
waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR)); waveOutWrite(this->hidden->shm->sound,
next_buffer = (next_buffer + 1) % NUM_BUFFERS; &(this->hidden->shm->wHdr[this->hidden->next_buffer]),
sizeof (WAVEHDR));
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
} }
static void static void
...@@ -236,13 +193,13 @@ MME_WaitDone(_THIS) ...@@ -236,13 +193,13 @@ MME_WaitDone(_THIS)
MMRESULT result; MMRESULT result;
int i; int i;
if (shm->sound) { if (this->hidden->shm->sound) {
for (i = 0; i < NUM_BUFFERS; i++) for (i = 0; i < NUM_BUFFERS; i++)
while (inUse[i]) { while (inUse[i]) {
mmeWaitForCallbacks(); mmeWaitForCallbacks();
mmeProcessCallbacks(); mmeProcessCallbacks();
} }
result = waveOutReset(shm->sound); result = waveOutReset(this->hidden->shm->sound);
if (result != MMSYSERR_NOERROR) if (result != MMSYSERR_NOERROR)
SetMMerror("waveOutReset()", result); SetMMerror("waveOutReset()", result);
mmeProcessCallbacks(); mmeProcessCallbacks();
...@@ -250,29 +207,54 @@ MME_WaitDone(_THIS) ...@@ -250,29 +207,54 @@ MME_WaitDone(_THIS)
} }
static void static void
MME_CloseAudio(_THIS) MME_CloseDevice(_THIS)
{ {
MMRESULT result; if (this->hidden != NULL) {
MMRESULT result;
if (mixbuf) { if (this->hidden->mixbuf) {
result = mmeFreeBuffer(mixbuf); result = mmeFreeBuffer(this->hidden->mixbuf);
if (result != MMSYSERR_NOERROR) if (result != MMSYSERR_NOERROR)
SetMMerror("mmeFreeBuffer", result); SetMMerror("mmeFreeBuffer", result);
mixbuf = NULL; this->hidden->mixbuf = NULL;
} }
if (shm) { if (this->hidden->shm) {
if (shm->sound) { if (this->hidden->shm->sound) {
result = waveOutClose(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) if (result != MMSYSERR_NOERROR)
SetMMerror("waveOutClose()", result); SetMMerror("mmeFreeMem()", result);
mmeProcessCallbacks(); this->hidden->shm = NULL;
} }
result = mmeFreeMem(shm);
if (result != MMSYSERR_NOERROR) SDL_free(this->hidden);
SetMMerror("mmeFreeMem()", result); this->hidden = NULL;
shm = 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
/* Allow access to a raw mixing buffer */ /* Allow access to a raw mixing buffer */
#ifndef _SDL_lowaudio_h #ifndef _SDL_mmeaudio_h
#define _SDL_lowaudio_h #define _SDL_mmeaudio_h
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2 #define NUM_BUFFERS 2
...@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData ...@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
int next_buffer; int next_buffer;
}; };
#define shm (this->hidden->shm) #endif /* _SDL_mmeaudio_h */
#define mixbuf (this->hidden->mixbuf)
#define next_buffer (this->hidden->next_buffer)
/* Old variable names */
#endif /* _SDL_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -32,106 +32,149 @@ ...@@ -32,106 +32,149 @@
#include "SDL_timer.h" #include "SDL_timer.h"
#include "SDL_audio.h" #include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_nasaudio.h" #include "SDL_nasaudio.h"
/* The tag name used by artsc audio */ /* The tag name used by nas audio */
#define NAS_DRIVER_NAME "nas" #define NAS_DRIVER_NAME "nas"
static struct SDL_PrivateAudioData *this2 = NULL; 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 static int
Audio_Available(void) load_nas_sym(const char *fn, void **addr)
{ {
AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL); *addr = SDL_LoadFunction(nas_handle, fn);
if (!aud) if (*addr == NULL) {
return 0; return 0;
}
AuCloseServer(aud);
return 1; return 1;
} }
static void /* cast funcs to char* first, to please GCC's strict aliasing rules. */
Audio_DeleteDevice(SDL_AudioDevice * device) #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_NAS_SYM(AuCloseServer);
SDL_free(device); 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 * #ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */ static void
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); UnloadNASLibrary(void)
if (this) { {
SDL_memset(this, 0, (sizeof *this)); if (nas_handle != NULL) {
this->hidden = (struct SDL_PrivateAudioData *) SDL_UnloadObject(nas_handle);
SDL_malloc((sizeof *this->hidden)); nas_handle = NULL;
} }
if ((this == NULL) || (this->hidden == NULL)) { }
SDL_OutOfMemory();
if (this) { static int
SDL_free(this); 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 */ #else
this->OpenAudio = NAS_OpenAudio;
this->WaitAudio = NAS_WaitAudio;
this->PlayAudio = NAS_PlayAudio;
this->GetAudioBuf = NAS_GetAudioBuf;
this->CloseAudio = NAS_CloseAudio;
this->free = Audio_DeleteDevice; static void
UnloadNASLibrary(void)
{
}
return this; static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
} }
AudioBootStrap NAS_bootstrap = { #endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
NAS_DRIVER_NAME, "Network Audio System",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */ /* This function waits until it is possible to write a full sound buffer */
static void static void
NAS_WaitAudio(_THIS) NAS_WaitDevice(_THIS)
{ {
while (this->hidden->buf_free < this->hidden->mixlen) { while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev; AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev); NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev); NAS_AuDispatchEvent(this->hidden->aud, &ev);
} }
} }
static void 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, while (this->hidden->mixlen > this->hidden->buf_free) {
in the hope that some of them is LowWater events telling us more /*
of the buffer is free now than what we think. */ * 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; AuEvent ev;
AuNextEvent(this->hidden->aud, AuTrue, &ev); NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
AuDispatchEvent(this->hidden->aud, &ev); NAS_AuDispatchEvent(this->hidden->aud, &ev);
} }
this->hidden->buf_free -= this->hidden->mixlen; this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */ /* 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->mixlen, this->hidden->mixbuf, AuFalse, NULL);
this->hidden->written += this->hidden->mixlen; this->hidden->written += this->hidden->mixlen;
...@@ -142,21 +185,25 @@ NAS_PlayAudio(_THIS) ...@@ -142,21 +185,25 @@ NAS_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
NAS_GetAudioBuf(_THIS) NAS_GetDeviceBuf(_THIS)
{ {
return (this->hidden->mixbuf); return (this->hidden->mixbuf);
} }
static void static void
NAS_CloseAudio(_THIS) NAS_CloseDevice(_THIS)
{ {
if (this->hidden->mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf); if (this->hidden->mixbuf != NULL) {
this->hidden->mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (this->hidden->aud) { }
AuCloseServer(this->hidden->aud); if (this->hidden->aud) {
this->hidden->aud = 0; 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) ...@@ -221,6 +268,7 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
static AuDeviceID static AuDeviceID
find_device(_THIS, int nch) find_device(_THIS, int nch)
{ {
/* These "Au" things are all macros, not functions... */
int i; int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
...@@ -233,46 +281,53 @@ find_device(_THIS, int nch) ...@@ -233,46 +281,53 @@ find_device(_THIS, int nch)
} }
static int static int
NAS_OpenAudio(_THIS, SDL_AudioSpec * spec) NAS_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
AuElement elms[3]; AuElement elms[3];
int buffer_size; int buffer_size;
SDL_AudioFormat test_format, format; 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 */ /* Try for a closest match on audio format */
format = 0; format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format); for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) { !format && test_format;) {
format = sdlformat_to_auformat(test_format); format = sdlformat_to_auformat(test_format);
if (format == AuNone) { if (format == AuNone) {
test_format = SDL_NextAudioFormat(); test_format = SDL_NextAudioFormat();
} }
} }
if (format == 0) { if (format == 0) {
SDL_SetError("Couldn't find any hardware audio formats"); NAS_CloseDevice(this);
return (-1); 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) { if (this->hidden->aud == 0) {
SDL_SetError("Couldn't open connection to NAS server"); NAS_CloseDevice(this);
return (-1); 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) if ((this->hidden->dev == AuNone)
|| (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) { || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
AuCloseServer(this->hidden->aud); NAS_CloseDevice(this);
this->hidden->aud = 0; SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
SDL_SetError("Couldn't find a fitting playback device on NAS server"); return 0;
return (-1);
} }
buffer_size = spec->freq; buffer_size = this->spec.freq;
if (buffer_size < 4096) if (buffer_size < 4096)
buffer_size = 4096; buffer_size = 4096;
...@@ -280,35 +335,70 @@ NAS_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -280,35 +335,70 @@ NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */ buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
/* Calculate the final parameters for this audio specification */ /* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
this2 = this->hidden; 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); 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); AuUnlimitedSamples, 0, NULL);
AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
NULL); AuTrue, 2, elms, NULL);
AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler, this->hidden->flow, event_handler,
(AuPointer) NULL); (AuPointer) NULL);
AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
/* Allocate mixing buffer */ /* Allocate mixing buffer */
this->hidden->mixlen = spec->size; this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return (-1); NAS_CloseDevice(this);
SDL_OutOfMemory();
return 0;
} }
SDL_memset(this->hidden->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) */
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData ...@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
AuFlowID flow; AuFlowID flow;
AuDeviceID dev; AuDeviceID dev;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */ /* Raw mixing buffer */
Uint8 *mixbuf; Uint8 *mixbuf;
int mixlen; int mixlen;
...@@ -60,4 +57,5 @@ struct SDL_PrivateAudioData ...@@ -60,4 +57,5 @@ struct SDL_PrivateAudioData
int buf_free; int buf_free;
}; };
#endif /* _SDL_nasaudio_h */ #endif /* _SDL_nasaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -69,13 +69,13 @@ struct BuggyCards buggycards[QSA_WA_CARDS] = { ...@@ -69,13 +69,13 @@ struct BuggyCards buggycards[QSA_WA_CARDS] = {
{"Vortex 8830", QSA_MMAP_WORKAROUND}, {"Vortex 8830", QSA_MMAP_WORKAROUND},
}; };
/* Audio driver functions */
static void NTO_ThreadInit(_THIS); static inline void
static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec); NTO_SetError(const char *fn, int rval)
static void NTO_WaitAudio(_THIS); {
static void NTO_PlayAudio(_THIS); SDL_SetError("NTO: %s failed: %s", fn, snd_strerror(rval));
static Uint8 *NTO_GetAudioBuf(_THIS); }
static void NTO_CloseAudio(_THIS);
/* card names check to apply the workarounds */ /* card names check to apply the workarounds */
static int static int
...@@ -84,7 +84,7 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor) ...@@ -84,7 +84,7 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
char scardname[33]; char scardname[33];
int it; int it;
if (snd_card_get_name(cardno, scardname, 32) < 0) { if (snd_card_get_name(this->hidden->cardno, scardname, 32) < 0) {
return 0; return 0;
} }
...@@ -102,11 +102,10 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor) ...@@ -102,11 +102,10 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
static void static void
NTO_ThreadInit(_THIS) NTO_ThreadInit(_THIS)
{ {
int status;
struct sched_param param; struct sched_param param;
int status = SchedGet(0, 0, &param);
/* increasing default 10 priority to 25 to avoid jerky sound */ /* increasing default 10 priority to 25 to avoid jerky sound */
status = SchedGet(0, 0, &param);
param.sched_priority = param.sched_curpriority + 15; param.sched_priority = param.sched_curpriority + 15;
status = SchedSet(0, 0, SCHED_NOCHANGE, &param); status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
} }
...@@ -130,111 +129,26 @@ NTO_InitAudioParams(snd_pcm_channel_params_t * cpars) ...@@ -130,111 +129,26 @@ NTO_InitAudioParams(snd_pcm_channel_params_t * cpars)
cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; 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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
NTO_WaitAudio(_THIS) NTO_WaitDevice(_THIS)
{ {
fd_set wfds; fd_set wfds;
int selectret; int selectret;
FD_ZERO(&wfds); FD_ZERO(&wfds);
FD_SET(audio_fd, &wfds); FD_SET(this->hidden->audio_fd, &wfds);
do { do {
selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL); selectret = select(this->hidden->audio_fd+1, NULL, &wfds, NULL, NULL);
switch (selectret) { switch (selectret) {
case -1: case -1:
case 0: case 0:
SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", SDL_SetError("NTO: select() failed: %s\n", strerror(errno));
strerror(errno));
return; return;
default: default:
if (FD_ISSET(audio_fd, &wfds)) { if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
return; return;
} }
break; break;
...@@ -244,22 +158,24 @@ NTO_WaitAudio(_THIS) ...@@ -244,22 +158,24 @@ NTO_WaitAudio(_THIS)
} }
static void static void
NTO_PlayAudio(_THIS) NTO_PlayDevice(_THIS)
{ {
snd_pcm_channel_status_t cstatus;
int written, rval; int written, rval;
int towrite; int towrite;
void *pcmbuffer; void *pcmbuffer;
if (!this->enabled) { if ((!this->enabled) || (!this->hidden)) {
return; return;
} }
towrite = this->spec.size; towrite = this->spec.size;
pcmbuffer = pcm_buf; pcmbuffer = this->hidden->pcm_buf;
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */ /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do { 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 (written != towrite) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
/* Let a little CPU time go by and try to write again */ /* Let a little CPU time go by and try to write again */
...@@ -268,33 +184,28 @@ NTO_PlayAudio(_THIS) ...@@ -268,33 +184,28 @@ NTO_PlayAudio(_THIS)
towrite -= written; towrite -= written;
pcmbuffer += written * this->spec.channels; pcmbuffer += written * this->spec.channels;
continue; continue;
} else { } else if ((errno == EINVAL) || (errno == EIO)) {
if ((errno == EINVAL) || (errno == EIO)) { SDL_memset(&cstatus, 0, sizeof (cstatus));
SDL_memset(&cstatus, 0, sizeof(cstatus)); cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; rval = snd_pcm_plugin_status(this->hidden->audio_handle,
if ((rval = &cstatus);
snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) { if (rval < 0) {
SDL_SetError NTO_SetError("snd_pcm_plugin_status", rval);
("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", return;
snd_strerror(rval)); }
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; 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 { } else {
/* we wrote all remaining data */ /* we wrote all remaining data */
...@@ -308,77 +219,74 @@ NTO_PlayAudio(_THIS) ...@@ -308,77 +219,74 @@ NTO_PlayAudio(_THIS)
if (towrite != 0) { if (towrite != 0) {
this->enabled = 0; this->enabled = 0;
} }
return;
} }
static Uint8 * static Uint8 *
NTO_GetAudioBuf(_THIS) NTO_GetDeviceBuf(_THIS)
{ {
return pcm_buf; return this->hidden->pcm_buf;
} }
static void static void
NTO_CloseAudio(_THIS) NTO_CloseDevice(_THIS)
{ {
int rval; if (this->hidden != NULL) {
if (this->hidden->audio_handle != NULL) {
this->enabled = 0; snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
if (audio_handle != NULL) { snd_pcm_close(this->hidden->audio_handle);
if ((rval = this->hidden->audio_handle = NULL;
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 ((rval = snd_pcm_close(audio_handle)) < 0) { if (this->hidden->pcm_buf != NULL) {
SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n", SDL_FreeAudioMem(this->hidden->pcm_buf);
snd_strerror(rval)); this->hidden->pcm_buf = NULL;
return;
} }
audio_handle = NULL; SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int static int
NTO_OpenAudio(_THIS, SDL_AudioSpec * spec) NTO_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
int rval; int rval = 0;
int format; int format = 0;
SDL_AudioFormat test_format; SDL_AudioFormat test_format = 0;
int found; int found = 0;
snd_pcm_channel_setup_t csetup;
audio_handle = NULL; snd_pcm_channel_params_t cparams;
this->enabled = 0;
if (pcm_buf != NULL) { /* Initialize all variables that we clean on shutdown */
SDL_FreeAudioMem(pcm_buf); this->hidden = (struct SDL_PrivateAudioData *)
pcm_buf = NULL; 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 */ /* initialize channel transfer parameters to default */
NTO_InitAudioParams(&cparams); NTO_InitAudioParams(&cparams);
/* Open the audio device */ /* Open the audio device */
rval = rval = snd_pcm_open_preferred(&this->hidden->audio_handle,
snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS); &this->hidden->cardno,
&this->hidden->deviceno, OPEN_FLAGS);
if (rval < 0) { if (rval < 0) {
SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", NTO_CloseDevice(this);
snd_strerror(rval)); NTO_SetError("snd_pcm_open", rval);
return (-1); return 0;
} }
if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) { if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
/* enable count status parameter */ /* enable count status parameter */
if ((rval = rval = snd_pcm_plugin_set_disable(this->hidden->audio_handle,
snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP);
PLUGIN_DISABLE_MMAP)) < 0) { if (rval < 0) {
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", NTO_CloseDevice(this);
snd_strerror(rval)); NTO_SetError("snd_pcm_plugin_set_disable", rval);
return (-1); return 0;
} }
} }
...@@ -387,7 +295,7 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -387,7 +295,7 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
found = 0; 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 */ /* if match found set format to equivalent ALSA format */
switch (test_format) { switch (test_format) {
case AUDIO_U8: case AUDIO_U8:
...@@ -441,86 +349,115 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -441,86 +349,115 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
/* assumes test_format not 0 on success */ /* assumes test_format not 0 on success */
if (test_format == 0) { if (test_format == 0) {
SDL_SetError NTO_CloseDevice(this);
("NTO_OpenAudio(): Couldn't find any hardware audio formats"); SDL_SetError("NTO: Couldn't find any hardware audio formats");
return (-1); return 0;
} }
spec->format = test_format; this->spec.format = test_format;
/* Set the audio format */ /* Set the audio format */
cparams.format.format = format; cparams.format.format = format;
/* Set mono or stereo audio (currently only two channels supported) */ /* Set mono or stereo audio (currently only two channels supported) */
cparams.format.voices = spec->channels; cparams.format.voices = this->spec.channels;
/* Set rate */ /* Set rate */
cparams.format.rate = spec->freq; cparams.format.rate = this->spec.freq;
/* Setup the transfer parameters according to cparams */ /* 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) { if (rval < 0) {
SDL_SetError NTO_CloseDevice(this);
("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", NTO_SetError("snd_pcm_channel_params", rval);
snd_strerror(rval)); return 0;
return (-1);
} }
/* Make sure channel is setup right one last time */ /* 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; csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) { if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n"); NTO_CloseDevice(this);
return -1; SDL_SetError("NTO: Unable to setup playback channel\n");
return 0;
} }
/* Calculate the final parameters for this audio specification */ /* 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) { if (this->hidden->pcm_len == 0) {
pcm_len = this->hidden->pcm_len =
csetup.buf.block.frag_size * spec->channels * csetup.buf.block.frag_size * this->spec.channels *
(snd_pcm_format_width(format) / 8); (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); this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
if (pcm_buf == NULL) { if (this->hidden->pcm_buf == NULL) {
SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n"); NTO_CloseDevice(this);
return (-1); 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 */ /* get the file descriptor */
if ((audio_fd = this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle,
snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
SND_PCM_CHANNEL_PLAYBACK)) < 0) { if (this->hidden->audio_fd < 0) {
SDL_SetError NTO_CloseDevice(this);
("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", NTO_SetError("snd_pcm_file_descriptor", rval);
snd_strerror(rval)); return 0;
return (-1);
} }
/* Trigger audio playback */ /* 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) { if (rval < 0) {
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", NTO_CloseDevice(this);
snd_strerror(rval)); NTO_SetError("snd_pcm_plugin_prepare", rval);
return (-1); 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. :-) */ static int
return (0); 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -47,23 +47,7 @@ struct SDL_PrivateAudioData ...@@ -47,23 +47,7 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */ /* Raw mixing buffer */
Uint8 *pcm_buf; Uint8 *pcm_buf;
Uint32 pcm_len; 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__ */ #endif /* __SDL_NTO_AUDIO_H__ */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -30,16 +30,17 @@ ...@@ -30,16 +30,17 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "SDL_timer.h" #include "SDL_timer.h"
#include "SDL_audio.h" #include "SDL_audio.h"
#include "SDL_stdinc.h"
#include "../SDL_audiomem.h" #include "../SDL_audiomem.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_paudio.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. /* 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. */ * I guess nobody ever uses audio... Shame over AIX header files. */
...@@ -48,94 +49,95 @@ ...@@ -48,94 +49,95 @@
#include <sys/audio.h> #include <sys/audio.h>
/* The tag name used by paud audio */ /* 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 */ /* Open the audio device for playback, and don't block if busy */
/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */ /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
#define OPEN_FLAGS O_WRONLY #define OPEN_FLAGS O_WRONLY
/* Audio driver functions */ /* Get the name of the audio device we use for output */
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);
/* 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 static int
Audio_Available(void) OpenUserDefinedDevice(char *path, int maxlen, int flags)
{ {
const char *audiodev;
int fd; int fd;
int available;
available = 0; /* Figure out what our audio device is */
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
if (fd >= 0) { audiodev = SDL_getenv("AUDIODEV");
available = 1;
close(fd);
} }
return (available); if (audiodev == NULL) {
} return -1;
}
static void fd = open(audiodev, flags, 0);
Audio_DeleteDevice(SDL_AudioDevice * device) if (path != NULL) {
{ SDL_strlcpy(path, audiodev, maxlen);
SDL_free(device->hidden); path[maxlen - 1] = '\0';
SDL_free(device); }
return fd;
} }
static SDL_AudioDevice * static int
Audio_CreateDevice(int devindex) 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 */ if (fd != -1) {
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); return fd;
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(); /* !!! FIXME: do we really need a table here? */
if (this) { while (devsettings[cycle][0] != '\0') {
SDL_free(this); 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)); return -1;
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;
} }
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 */ /* This function waits until it is possible to write a full sound buffer */
static void static void
Paud_WaitAudio(_THIS) PAUDIO_WaitDevice(_THIS)
{ {
fd_set fdset; fd_set fdset;
/* See if we need to use timed audio synchronization */ /* See if we need to use timed audio synchronization */
if (frame_ticks) { if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */ /* Use timer for general audio synchronization */
Sint32 ticks; Sint32 ticks;
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
if (ticks > 0) { if (ticks > 0) {
SDL_Delay(ticks); SDL_Delay(ticks);
} }
...@@ -145,9 +147,9 @@ Paud_WaitAudio(_THIS) ...@@ -145,9 +147,9 @@ Paud_WaitAudio(_THIS)
/* Use select() for audio synchronization */ /* Use select() for audio synchronization */
struct timeval timeout; struct timeval timeout;
FD_ZERO(&fdset); 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 #ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't get audio buffer information\n"); fprintf(stderr, "Couldn't get audio buffer information\n");
#endif #endif
...@@ -168,7 +170,7 @@ Paud_WaitAudio(_THIS) ...@@ -168,7 +170,7 @@ Paud_WaitAudio(_THIS)
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n"); fprintf(stderr, "Waiting for audio to get ready\n");
#endif #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 = const char *message =
"Audio timeout - buggy audio driver? (disabled)"; "Audio timeout - buggy audio driver? (disabled)";
/* /*
...@@ -179,7 +181,7 @@ Paud_WaitAudio(_THIS) ...@@ -179,7 +181,7 @@ Paud_WaitAudio(_THIS)
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
this->enabled = 0; this->enabled = 0;
/* Don't try to close - may hang */ /* Don't try to close - may hang */
audio_fd = -1; this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n"); fprintf(stderr, "Done disabling audio\n");
#endif #endif
...@@ -191,13 +193,15 @@ Paud_WaitAudio(_THIS) ...@@ -191,13 +193,15 @@ Paud_WaitAudio(_THIS)
} }
static void 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 */ /* Write the audio data, checking for EAGAIN on broken audio drivers */
do { do {
written = write(audio_fd, mixbuf, mixlen); written = write(this->hidden->audio_fd, mixbuf, mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */ SDL_Delay(1); /* Let a little CPU time go by */
} }
...@@ -206,8 +210,8 @@ Paud_PlayAudio(_THIS) ...@@ -206,8 +210,8 @@ Paud_PlayAudio(_THIS)
((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* If timer synchronization is enabled, set the next write frame */ /* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) { if (this->hidden->frame_ticks) {
next_frame += frame_ticks; this->hidden->next_frame += this->hidden->frame_ticks;
} }
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
...@@ -220,28 +224,34 @@ Paud_PlayAudio(_THIS) ...@@ -220,28 +224,34 @@ Paud_PlayAudio(_THIS)
} }
static Uint8 * static Uint8 *
Paud_GetAudioBuf(_THIS) PAUDIO_GetDeviceBuf(_THIS)
{ {
return mixbuf; return this->hidden->mixbuf;
} }
static void static void
Paud_CloseAudio(_THIS) PAUDIO_CloseDevice(_THIS)
{ {
if (mixbuf != NULL) { if (this->hidden != NULL) {
SDL_FreeAudioMem(mixbuf); if (this->hidden->mixbuf != NULL) {
mixbuf = NULL; SDL_FreeAudioMem(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_fd >= 0) { }
close(audio_fd); if (this->hidden->audio_fd >= 0) {
audio_fd = -1; close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
} }
} }
static int 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]; char audiodev[1024];
const char *err = NULL;
int format; int format;
int bytes_per_sample; int bytes_per_sample;
SDL_AudioFormat test_format; SDL_AudioFormat test_format;
...@@ -250,32 +260,40 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -250,32 +260,40 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
audio_status paud_status; audio_status paud_status;
audio_control paud_control; audio_control paud_control;
audio_change paud_change; audio_change paud_change;
int fd = -1;
/* Reset the timer synchronization flag */ /* Initialize all variables that we clean on shutdown */
frame_ticks = 0.0; 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 */ /* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if (audio_fd < 0) { this->hidden->audio_fd = fd;
if (fd < 0) {
PAUDIO_CloseDevice(this);
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); 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 * We can't set the buffer size - just ask the device for the maximum
* that we can have. * 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"); SDL_SetError("Couldn't get audio buffer information");
return -1; return 0;
} }
mixbuf = NULL; if (this->spec.channels > 1)
this->spec.channels = 2;
if (spec->channels > 1)
spec->channels = 2;
else else
spec->channels = 1; this->spec.channels = 1;
/* /*
* Fields in the audio_init structure: * Fields in the audio_init structure:
...@@ -322,14 +340,14 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -322,14 +340,14 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
* paud.position_resolution; * smallest increment for position * paud.position_resolution; * smallest increment for position
*/ */
paud_init.srate = spec->freq; paud_init.srate = this->spec.freq;
paud_init.mode = PCM; paud_init.mode = PCM;
paud_init.operation = PLAY; paud_init.operation = PLAY;
paud_init.channels = spec->channels; paud_init.channels = this->spec.channels;
/* Try for a closest match on audio format */ /* Try for a closest match on audio format */
format = 0; format = 0;
for (test_format = SDL_FirstAudioFormat(spec->format); for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) { !format && test_format;) {
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format); fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
...@@ -382,31 +400,32 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -382,31 +400,32 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n"); fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif #endif
PAUDIO_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats"); 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 * 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 * that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and * to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway. * the device's own buffer that we are filling with write() anyway.
* *
* We calculate spec->samples like this because SDL_CalculateAudioSpec() * We calculate this->spec.samples like this because
* will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2) * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
* into spec->size in return. * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
*/ */
if (paud_bufinfo.request_buf_cap == 1) { if (paud_bufinfo.request_buf_cap == 1) {
spec->samples = paud_bufinfo.write_buf_cap this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / spec->channels; / bytes_per_sample / this->spec.channels;
} else { } else {
spec->samples = paud_bufinfo.write_buf_cap this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / spec->channels / 2; / 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 * The AIX paud device init can't modify the values of the audio_init
...@@ -416,47 +435,44 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -416,47 +435,44 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
* /dev/paud supports all of the encoding formats, so we don't need * /dev/paud supports all of the encoding formats, so we don't need
* to do anything like reopening the device, either. * 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) { switch (paud_init.rc) {
case 1: case 1:
SDL_SetError err = "Couldn't set audio format: DSP can't do play requests";
("Couldn't set audio format: DSP can't do play requests");
return -1;
break; break;
case 2: case 2:
SDL_SetError err = "Couldn't set audio format: DSP can't do record requests";
("Couldn't set audio format: DSP can't do record requests");
return -1;
break; break;
case 4: case 4:
SDL_SetError("Couldn't set audio format: request was invalid"); err = "Couldn't set audio format: request was invalid";
return -1;
break; break;
case 5: case 5:
SDL_SetError err = "Couldn't set audio format: conflict with open's flags";
("Couldn't set audio format: conflict with open's flags");
return -1;
break; break;
case 6: case 6:
SDL_SetError err = "Couldn't set audio format: out of DSP MIPS or memory";
("Couldn't set audio format: out of DSP MIPS or memory");
return -1;
break; break;
default: default:
SDL_SetError err = "Couldn't set audio format: not documented in sys/audio.h";
("Couldn't set audio format: not documented in sys/audio.h");
return -1;
break; break;
} }
} }
if (err != NULL) {
PAUDIO_CloseDevice(this);
SDL_SetError("Paudio: %s", err);
return 0;
}
/* Allocate mixing buffer */ /* Allocate mixing buffer */
mixlen = spec->size; this->hidden->mixlen = this->spec.size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (mixbuf == NULL) { if (this->hidden->mixbuf == NULL) {
return -1; 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. * Set some paramters: full volume, first speaker that we can find.
...@@ -475,7 +491,7 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -475,7 +491,7 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
paud_control.ioctl_request = AUDIO_CHANGE; paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char *) &paud_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 #ifdef DEBUG_AUDIO
fprintf(stderr, "Can't change audio display settings\n"); fprintf(stderr, "Can't change audio display settings\n");
#endif #endif
...@@ -487,29 +503,49 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) ...@@ -487,29 +503,49 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
*/ */
paud_control.ioctl_request = AUDIO_START; paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0; 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 #ifdef DEBUG_AUDIO
fprintf(stderr, "Can't start audio play\n"); fprintf(stderr, "Can't start audio play\n");
#endif #endif
SDL_SetError("Can't start audio play"); SDL_SetError("Can't start audio play");
return -1; return 0;
} }
/* Check to see if we need to use select() workaround */ /* Check to see if we need to use select() workaround */
{ if (workaround != NULL) {
char *workaround; this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
workaround = SDL_getenv("SDL_DSP_NOSELECT"); this->spec.freq;
if (workaround) { this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
}
} }
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */ /* 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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -34,9 +34,6 @@ struct SDL_PrivateAudioData ...@@ -34,9 +34,6 @@ struct SDL_PrivateAudioData
/* The file descriptor for the audio device */ /* The file descriptor for the audio device */
int audio_fd; int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */ /* Raw mixing buffer */
Uint8 *mixbuf; Uint8 *mixbuf;
int mixlen; int mixlen;
...@@ -47,13 +44,5 @@ struct SDL_PrivateAudioData ...@@ -47,13 +44,5 @@ struct SDL_PrivateAudioData
}; };
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ #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 */ #endif /* _SDL_paudaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* 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 SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga Copyright (C) 1997-2006 Sam Lantinga
...@@ -116,7 +121,7 @@ Audio_CreateDevice(int devindex) ...@@ -116,7 +121,7 @@ Audio_CreateDevice(int devindex)
AudioBootStrap SUNAUDIO_bootstrap = { AudioBootStrap SUNAUDIO_bootstrap = {
"audio", "UNIX /dev/audio interface", "audio", "UNIX /dev/audio interface",
Audio_Available, Audio_CreateDevice Audio_Available, Audio_CreateDevice, 0
}; };
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
......
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_sunaudio_h
#define _SDL_lowaudio_h #define _SDL_sunaudio_h
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
...@@ -53,5 +53,6 @@ struct SDL_PrivateAudioData ...@@ -53,5 +53,6 @@ struct SDL_PrivateAudioData
#define fragsize (this->hidden->fragsize) #define fragsize (this->hidden->fragsize)
#define frequency (this->hidden->frequency) #define frequency (this->hidden->frequency)
#endif /* _SDL_lowaudio_h */ #endif /* _SDL_sunaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* 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 SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga Copyright (C) 1997-2006 Sam Lantinga
...@@ -36,7 +41,6 @@ ...@@ -36,7 +41,6 @@
#include "SDL_audio.h" #include "SDL_audio.h"
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_umsaudio.h" #include "SDL_umsaudio.h"
/* The tag name used by UMS audio */ /* The tag name used by UMS audio */
...@@ -152,7 +156,7 @@ Audio_CreateDevice(int devindex) ...@@ -152,7 +156,7 @@ Audio_CreateDevice(int devindex)
AudioBootStrap UMS_bootstrap = { AudioBootStrap UMS_bootstrap = {
UMS_DRIVER_NAME, "AIX UMS audio", UMS_DRIVER_NAME, "AIX UMS audio",
Audio_Available, Audio_CreateDevice Audio_Available, Audio_CreateDevice, 0
}; };
static Uint8 * static Uint8 *
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData struct SDL_PrivateAudioData
......
...@@ -35,71 +35,13 @@ ...@@ -35,71 +35,13 @@
#include "win_ce_semaphore.h" #include "win_ce_semaphore.h"
#endif #endif
#if defined(_WIN32_WCE)
/* Audio driver functions */ #define WINDOWS_OS_NAME "Windows CE/PocketPC"
static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec); #elif defined(WIN64)
static void DIB_ThreadInit(_THIS); #define WINDOWS_OS_NAME "Win64"
static void DIB_WaitAudio(_THIS); #else
static Uint8 *DIB_GetAudioBuf(_THIS); #define WINDOWS_OS_NAME "Win32"
static void DIB_PlayAudio(_THIS); #endif
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
};
/* The Win32 callback for filling the WAVE device */ /* The Win32 callback for filling the WAVE device */
static void CALLBACK static void CALLBACK
...@@ -114,9 +56,9 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, ...@@ -114,9 +56,9 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
/* Signal that we are done playing a buffer */ /* Signal that we are done playing a buffer */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
ReleaseSemaphoreCE(audio_sem, 1, NULL); ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
#else #else
ReleaseSemaphore(audio_sem, 1, NULL); ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
#endif #endif
} }
...@@ -146,48 +88,47 @@ SetMMerror(char *function, MMRESULT code) ...@@ -146,48 +88,47 @@ SetMMerror(char *function, MMRESULT code)
/* Set high priority for the audio thread */ /* Set high priority for the audio thread */
static void static void
DIB_ThreadInit(_THIS) WINWAVEOUT_ThreadInit(_THIS)
{ {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
} }
void void
DIB_WaitAudio(_THIS) WINWAVEOUT_WaitDevice(_THIS)
{ {
/* Wait for an audio chunk to finish */ /* Wait for an audio chunk to finish */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
WaitForSemaphoreCE(audio_sem, INFINITE); WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
#else #else
WaitForSingleObject(audio_sem, INFINITE); WaitForSingleObject(this->hidden->audio_sem, INFINITE);
#endif #endif
} }
Uint8 * Uint8 *
DIB_GetAudioBuf(_THIS) WINWAVEOUT_GetDeviceBuf(_THIS)
{ {
Uint8 *retval; return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData);
retval = (Uint8 *) (wavebuf[next_buffer].lpData);
return retval;
} }
void void
DIB_PlayAudio(_THIS) WINWAVEOUT_PlayDevice(_THIS)
{ {
/* Queue it up */ /* Queue it up */
waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0])); waveOutWrite(this->hidden->sound,
next_buffer = (next_buffer + 1) % NUM_BUFFERS; &this->hidden->wavebuf[this->hidden->next_buffer],
sizeof (this->hidden->wavebuf[0]));
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
} }
void void
DIB_WaitDone(_THIS) WINWAVEOUT_WaitDone(_THIS)
{ {
int i, left; int i, left;
do { do {
left = NUM_BUFFERS; left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) { for (i = 0; i < NUM_BUFFERS; ++i) {
if (wavebuf[i].dwFlags & WHDR_DONE) { if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
--left; --left;
} }
} }
...@@ -199,143 +140,197 @@ DIB_WaitDone(_THIS) ...@@ -199,143 +140,197 @@ DIB_WaitDone(_THIS)
} }
void void
DIB_CloseAudio(_THIS) WINWAVEOUT_CloseDevice(_THIS)
{ {
int i;
/* Close up audio */ /* Close up audio */
if (audio_sem) { if (this->hidden != NULL) {
int i;
if (this->hidden->audio_sem) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
CloseSynchHandle(audio_sem); CloseSynchHandle(this->hidden->audio_sem);
#else #else
CloseHandle(audio_sem); CloseHandle(this->hidden->audio_sem);
#endif #endif
} this->hidden->audio_sem = 0;
if (sound) { }
waveOutClose(sound);
}
/* Clean up mixing buffers */ if (this->hidden->sound) {
for (i = 0; i < NUM_BUFFERS; ++i) { waveOutClose(this->hidden->sound);
if (wavebuf[i].dwUser != 0xFFFF) { this->hidden->sound = 0;
waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
wavebuf[i].dwUser = 0xFFFF;
} }
}
/* Free raw mixing buffer */ /* Clean up mixing buffers */
if (mixbuf != NULL) { for (i = 0; i < NUM_BUFFERS; ++i) {
SDL_free(mixbuf); if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
mixbuf = NULL; 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 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; MMRESULT result;
int i;
WAVEFORMATEX waveformat; 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 */ /* Initialize the wavebuf structures for closing */
sound = NULL;
audio_sem = NULL;
for (i = 0; i < NUM_BUFFERS; ++i) for (i = 0; i < NUM_BUFFERS; ++i)
wavebuf[i].dwUser = 0xFFFF; this->hidden->wavebuf[i].dwUser = 0xFFFF;
mixbuf = NULL;
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 */ /* Set basic WAVE format parameters */
SDL_memset(&waveformat, 0, sizeof(waveformat)); SDL_memset(&waveformat, '\0', sizeof (waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
/* Determine the audio parameters from the AudioSpec */ if (this->spec.channels > 2)
switch (SDL_AUDIO_BITSIZE(spec->format)) { this->spec.channels = 2; /* !!! FIXME: is this right? */
case 8:
/* Unsigned 8 bit audio data */ waveformat.nChannels = this->spec.channels;
spec->format = AUDIO_U8; waveformat.nSamplesPerSec = this->spec.freq;
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;
waveformat.nBlockAlign = waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8); waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec = waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign; waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */ /* Check the buffer size -- minimum of 1/4 second (word aligned) */
if (spec->samples < (spec->freq / 4)) if (this->spec.samples < (this->spec.freq / 4))
spec->samples = ((spec->freq / 4) + 3) & ~3; this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
/* Update the fragment size as size in bytes */ /* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */ /* Open the audio device */
result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat, result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
(DWORD_PTR) FillSound, (DWORD_PTR) this, (DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION); CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutOpen()", result); SetMMerror("waveOutOpen()", result);
return (-1); return 0;
} }
#ifdef SOUND_DEBUG #ifdef SOUND_DEBUG
/* Check the sound device we retrieved */ /* Check the sound device we retrieved */
{ {
WAVEOUTCAPS caps; WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps)); result = waveOutGetDevCaps((UINT) this->hidden->sound,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutGetDevCaps()", result); SetMMerror("waveOutGetDevCaps()", result);
return (-1); return 0;
} }
printf("Audio device: %s\n", caps.szPname); printf("Audio device: %s\n", caps.szPname);
} }
#endif #endif
/* Create the audio buffer semaphore */ /* Create the audio buffer semaphore */
this->hidden->audio_sem =
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) #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 #else
audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
#endif #endif
if (audio_sem == NULL) { if (this->hidden->audio_sem == NULL) {
WINWAVEOUT_CloseDevice(this);
SDL_SetError("Couldn't create semaphore"); SDL_SetError("Couldn't create semaphore");
return (-1); return 0;
} }
/* Create the sound buffers */ /* 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) { if (mixbuf == NULL) {
SDL_SetError("Out of memory"); WINWAVEOUT_CloseDevice(this);
return (-1); SDL_OutOfMemory();
return 0;
} }
for (i = 0; i < NUM_BUFFERS; ++i) { for (i = 0; i < NUM_BUFFERS; ++i) {
SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i])); SDL_memset(&this->hidden->wavebuf[i], '\0',
wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size]; sizeof (this->hidden->wavebuf[i]));
wavebuf[i].dwBufferLength = spec->size; this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
wavebuf[i].dwFlags = WHDR_DONE; this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i])); 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) { if (result != MMSYSERR_NOERROR) {
WINWAVEOUT_CloseDevice(this);
SetMMerror("waveOutPrepareHeader()", result); SetMMerror("waveOutPrepareHeader()", result);
return (-1); return 0;
} }
} }
/* Ready to go! */ return 1; /* Ready to go! */
next_buffer = 0;
return (0);
} }
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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_dibaudio_h
#define _SDL_lowaudio_h #define _SDL_dibaudio_h
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2 /* -- Don't lower this! */ #define NUM_BUFFERS 2 /* -- Don't lower this! */
...@@ -40,12 +40,6 @@ struct SDL_PrivateAudioData ...@@ -40,12 +40,6 @@ struct SDL_PrivateAudioData
int next_buffer; int next_buffer;
}; };
/* Old variable names */ #endif /* _SDL_dibaudio_h */
#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_lowaudio_h */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -28,160 +28,65 @@ ...@@ -28,160 +28,65 @@
#include "../SDL_audio_c.h" #include "../SDL_audio_c.h"
#include "SDL_dx5audio.h" #include "SDL_dx5audio.h"
/* Define this if you want to use DirectX 6 DirectSoundNotify interface */ /* !!! FIXME: move this somewhere that other drivers can use it... */
//#define USE_POSITION_NOTIFY #if defined(_WIN32_WCE)
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
/* DirectX function pointers for audio */ #elif defined(WIN64)
HRESULT(WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN); #define WINDOWS_OS_NAME "Win64"
#else
/* Audio driver functions */ #define WINDOWS_OS_NAME "Win32"
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);
#endif #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;
} /* DirectX function pointers for audio */
/* Clean up.. */
FreeLibrary(DSoundDLL);
}
return (dsound_ok);
}
/* Functions for loading the DirectX functions dynamically */
static HINSTANCE DSoundDLL = NULL; static HINSTANCE DSoundDLL = NULL;
static HRESULT (WINAPI *DSoundCreate)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN) = NULL;
static void static void
DX5_Unload(void) DSOUND_Unload(void)
{ {
if (DSoundDLL != NULL) { if (DSoundDLL != NULL) {
FreeLibrary(DSoundDLL); FreeLibrary(DSoundDLL);
DSoundCreate = NULL;
DSoundDLL = NULL;
} }
}
static int
DX5_Load(void)
{
int status;
DX5_Unload(); DSoundCreate = NULL;
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL")); DSoundDLL = NULL;
if (DSoundDLL != NULL) {
DSoundCreate = (void *) GetProcAddress(DSoundDLL,
TEXT("DirectSoundCreate"));
}
if (DSoundDLL && DSoundCreate) {
status = 0;
} else {
DX5_Unload();
status = -1;
}
return status;
} }
static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
DX5_Unload();
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice * static int
Audio_CreateDevice(int devindex) DSOUND_Load(void)
{ {
SDL_AudioDevice *this; int loaded = 0;
/* Load DirectX */ DSOUND_Unload();
if (DX5_Load() < 0) {
return (NULL);
}
/* Initialize all variables that we clean on shutdown */ DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); if (DSoundDLL == NULL) {
if (this) { SDL_SetError("DirectSound: failed to load DSOUND.DLL");
SDL_memset(this, 0, (sizeof *this)); } else {
this->hidden = (struct SDL_PrivateAudioData *) /* Now make sure we have DirectX 5 or better... */
SDL_malloc((sizeof *this->hidden)); /* (DirectSoundCaptureCreate was added in DX5) */
} if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) {
if ((this == NULL) || (this->hidden == NULL)) { SDL_SetError("DirectSound: System doesn't appear to have DX5.");
SDL_OutOfMemory(); } else {
if (this) { DSoundCreate = (void *) GetProcAddress(DSoundDLL,
SDL_free(this); TEXT("DirectSoundCreate"));
} }
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */ if (!DSoundCreate) {
this->OpenAudio = DX5_OpenAudio; SDL_SetError("DirectSound: Failed to find DirectSoundCreate");
this->ThreadInit = DX5_ThreadInit; } else {
this->WaitAudio = DX5_WaitAudio_BusyWait; loaded = 1;
this->PlayAudio = DX5_PlayAudio; }
this->GetAudioBuf = DX5_GetAudioBuf; }
this->WaitDone = DX5_WaitDone;
this->CloseAudio = DX5_CloseAudio;
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 static void
SetDSerror(const char *function, int code) SetDSerror(const char *function, int code)
...@@ -192,8 +97,7 @@ SetDSerror(const char *function, int code) ...@@ -192,8 +97,7 @@ SetDSerror(const char *function, int code)
errbuf[0] = 0; errbuf[0] = 0;
switch (code) { switch (code) {
case E_NOINTERFACE: case E_NOINTERFACE:
error = error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
"Unsupported interface\n-- Is DirectX 5.0 or later installed?";
break; break;
case DSERR_ALLOCATED: case DSERR_ALLOCATED:
error = "Audio device in use"; error = "Audio device in use";
...@@ -241,32 +145,36 @@ SetDSerror(const char *function, int code) ...@@ -241,32 +145,36 @@ SetDSerror(const char *function, int code)
/* DirectSound needs to be associated with a window */ /* DirectSound needs to be associated with a window */
static HWND mainwin = NULL; static HWND mainwin = NULL;
/* */ /* */
void void
DX5_SoundFocus(HWND hwnd) DSOUND_SoundFocus(HWND hwnd)
{ {
/* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
mainwin = hwnd; mainwin = hwnd;
} }
static void static void
DX5_ThreadInit(_THIS) DSOUND_ThreadInit(_THIS)
{ {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
} }
static void static void
DX5_WaitAudio_BusyWait(_THIS) DSOUND_WaitDevice(_THIS)
{ {
DWORD status; DWORD status = 0;
DWORD cursor, junk; DWORD cursor = 0;
HRESULT result; DWORD junk = 0;
HRESULT result = DS_OK;
/* Semi-busy wait, since we have no way of getting play notification /* Semi-busy wait, since we have no way of getting play notification
on a primary mixing buffer located in hardware (DirectX 5.0) 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 != DS_OK) {
if (result == DSERR_BUFFERLOST) { if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf); IDirectSoundBuffer_Restore(this->hidden->mixbuf);
} }
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCurrentPosition", result); SetDSerror("DirectSound GetCurrentPosition", result);
...@@ -274,21 +182,22 @@ DX5_WaitAudio_BusyWait(_THIS) ...@@ -274,21 +182,22 @@ DX5_WaitAudio_BusyWait(_THIS)
return; 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 */ /* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1); SDL_Delay(1);
/* Try to restore a lost sound buffer */ /* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(mixbuf, &status); IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) { if ((status & DSBSTATUS_BUFFERLOST)) {
IDirectSoundBuffer_Restore(mixbuf); IDirectSoundBuffer_Restore(this->hidden->mixbuf);
IDirectSoundBuffer_GetStatus(mixbuf, &status); IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) { if ((status & DSBSTATUS_BUFFERLOST)) {
break; break;
} }
} }
if (!(status & DSBSTATUS_PLAYING)) { 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) { if (result == DS_OK) {
continue; continue;
} }
...@@ -299,7 +208,7 @@ DX5_WaitAudio_BusyWait(_THIS) ...@@ -299,7 +208,7 @@ DX5_WaitAudio_BusyWait(_THIS)
} }
/* Find out where we are playing */ /* Find out where we are playing */
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor); &junk, &cursor);
if (result != DS_OK) { if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result); SetDSerror("DirectSound GetCurrentPosition", result);
...@@ -308,222 +217,122 @@ DX5_WaitAudio_BusyWait(_THIS) ...@@ -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 static void
DX5_PlayAudio(_THIS) DSOUND_PlayDevice(_THIS)
{ {
/* Unlock the buffer, allowing it to play */ /* Unlock the buffer, allowing it to play */
if (locked_buf) { if (this->hidden->locked_buf) {
IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0); IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
this->hidden->locked_buf,
this->hidden->mixlen, NULL, 0);
} }
} }
static Uint8 * static Uint8 *
DX5_GetAudioBuf(_THIS) DSOUND_GetDeviceBuf(_THIS)
{ {
DWORD cursor, junk; DWORD cursor = 0;
HRESULT result; DWORD junk = 0;
DWORD rawlen; HRESULT result = DS_OK;
DWORD rawlen = 0;
/* Figure out which blocks to fill next */ /* Figure out which blocks to fill next */
locked_buf = NULL; this->hidden->locked_buf = NULL;
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result == DSERR_BUFFERLOST) { if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf); IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor); &junk, &cursor);
} }
if (result != DS_OK) { if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result); SetDSerror("DirectSound GetCurrentPosition", result);
return (NULL); return (NULL);
} }
cursor /= mixlen; cursor /= this->hidden->mixlen;
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
/* Detect audio dropouts */ /* Detect audio dropouts */
{ {
DWORD spot = cursor; DWORD spot = cursor;
if (spot < lastchunk) { if (spot < this->hidden->lastchunk) {
spot += NUM_BUFFERS; spot += this->hidden->num_buffers;
} }
if (spot > lastchunk + 1) { if (spot > this->hidden->lastchunk + 1) {
fprintf(stderr, "Audio dropout, missed %d fragments\n", fprintf(stderr, "Audio dropout, missed %d fragments\n",
(spot - (lastchunk + 1))); (spot - (this->hidden->lastchunk + 1)));
} }
} }
#endif #endif
lastchunk = cursor; this->hidden->lastchunk = cursor;
cursor = (cursor + 1) % NUM_BUFFERS; cursor = (cursor + 1) % this->hidden->num_buffers;
cursor *= mixlen; cursor *= this->hidden->mixlen;
/* Lock the audio buffer */ /* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
(LPVOID *) & locked_buf, &rawlen, NULL, this->hidden->mixlen,
&junk, 0); (LPVOID *) &this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
if (result == DSERR_BUFFERLOST) { if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(mixbuf); IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
(LPVOID *) & locked_buf, &rawlen, this->hidden->mixlen,
NULL, &junk, 0); (LPVOID *) &this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
} }
if (result != DS_OK) { if (result != DS_OK) {
SetDSerror("DirectSound Lock", result); SetDSerror("DirectSound Lock", result);
return (NULL); return (NULL);
} }
return (locked_buf); return (this->hidden->locked_buf);
} }
static void static void
DX5_WaitDone(_THIS) DSOUND_WaitDone(_THIS)
{ {
Uint8 *stream; Uint8 *stream = DSOUND_GetDeviceBuf(this);
/* Wait for the playing chunk to finish */ /* Wait for the playing chunk to finish */
stream = this->GetAudioBuf(this);
if (stream != NULL) { if (stream != NULL) {
SDL_memset(stream, silence, mixlen); SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
this->PlayAudio(this); DSOUND_PlayDevice(this);
} }
this->WaitAudio(this); DSOUND_WaitDevice(this);
/* Stop the looping sound buffer */ /* Stop the looping sound buffer */
IDirectSoundBuffer_Stop(mixbuf); IDirectSoundBuffer_Stop(this->hidden->mixbuf);
} }
static void static void
DX5_CloseAudio(_THIS) DSOUND_CloseDevice(_THIS)
{ {
if (sound != NULL) { if (this->hidden != NULL) {
if (mixbuf != NULL) { if (this->hidden->sound != NULL) {
/* Clean up the audio buffer */ if (this->hidden->mixbuf != NULL) {
IDirectSoundBuffer_Release(mixbuf); /* Clean up the audio buffer */
mixbuf = NULL; IDirectSoundBuffer_Release(this->hidden->mixbuf);
} this->hidden->mixbuf = NULL;
if (audio_event != NULL) { }
CloseHandle(audio_event); IDirectSound_Release(this->hidden->sound);
audio_event = NULL; this->hidden->sound = NULL;
} }
IDirectSound_Release(sound);
sound = NULL;
}
}
#ifdef USE_PRIMARY_BUFFER SDL_free(this->hidden);
/* This function tries to create a primary audio buffer, and returns the this->hidden = NULL;
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);
} }
/* 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 /* This function tries to create a secondary audio buffer, and returns the
number of audio chunks available in the created buffer. number of audio chunks available in the created buffer.
*/ */
static int static int
CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, CreateSecondary(_THIS, HWND focus, WAVEFORMATEX *wavefmt)
LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
Uint32 chunksize)
{ {
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = this->hidden->mixbuf;
Uint32 chunksize = this->spec.size;
const int numchunks = 8; const int numchunks = 8;
HRESULT result; HRESULT result = DS_OK;
DSBUFFERDESC format; DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2; LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2; DWORD dwAudioBytes1, dwAudioBytes2;
...@@ -538,9 +347,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, ...@@ -538,9 +347,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
DSSCL_NORMAL); DSSCL_NORMAL);
} }
if (result != DS_OK) { if (result != DS_OK) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetCooperativeLevel", result); SetDSerror("DirectSound SetCooperativeLevel", result);
#endif
return (-1); return (-1);
} }
...@@ -548,9 +355,6 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, ...@@ -548,9 +355,6 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
SDL_memset(&format, 0, sizeof(format)); SDL_memset(&format, 0, sizeof(format));
format.dwSize = sizeof(format); format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
#ifdef USE_POSITION_NOTIFY
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
#endif
if (!focus) { if (!focus) {
format.dwFlags |= DSBCAPS_GLOBALFOCUS; format.dwFlags |= DSBCAPS_GLOBALFOCUS;
} else { } else {
...@@ -578,11 +382,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, ...@@ -578,11 +382,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
(LPVOID *) & pvAudioPtr2, &dwAudioBytes2, (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
DSBLOCK_ENTIREBUFFER); DSBLOCK_ENTIREBUFFER);
if (result == DS_OK) { if (result == DS_OK) {
if (wavefmt->wBitsPerSample == 8) { SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
} else {
SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
}
IDirectSoundBuffer_Unlock(*sndbuf, IDirectSoundBuffer_Unlock(*sndbuf,
(LPVOID) pvAudioPtr1, dwAudioBytes1, (LPVOID) pvAudioPtr1, dwAudioBytes1,
(LPVOID) pvAudioPtr2, dwAudioBytes2); (LPVOID) pvAudioPtr2, dwAudioBytes2);
...@@ -592,148 +392,125 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, ...@@ -592,148 +392,125 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
return (numchunks); return (numchunks);
} }
/* This function tries to set position notify events on the mixing buffer */
#ifdef USE_POSITION_NOTIFY
static int static int
CreateAudioEvent(_THIS) DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
{ {
LPDIRECTSOUNDNOTIFY notify;
DSBPOSITIONNOTIFY *notify_positions;
int i, retval;
HRESULT result; HRESULT result;
WAVEFORMATEX waveformat;
int valid_format = 0;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
/* Default to fail on exit */ /* !!! FIXME: handle devname */
retval = -1; /* !!! FIXME: handle iscapture */
notify = NULL;
/* Query for the interface */ /* Initialize all variables that we clean on shutdown */
result = IDirectSoundBuffer_QueryInterface(mixbuf, this->hidden = (struct SDL_PrivateAudioData *)
&IID_IDirectSoundNotify, SDL_malloc((sizeof *this->hidden));
(void *) &notify); if (this->hidden == NULL) {
if (result != DS_OK) { SDL_OutOfMemory();
goto done; return 0;
}
/* Allocate the notify structures */
notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc(NUM_BUFFERS *
sizeof
(*notify_positions));
if (notify_positions == NULL) {
goto done;
} }
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Create the notify event */ while ((!valid_format) && (test_format)) {
audio_event = CreateEvent(NULL, FALSE, FALSE, NULL); switch (test_format) {
if (audio_event == NULL) { case AUDIO_U8:
goto done; case AUDIO_S16:
case AUDIO_S32:
this->spec.format = test_format;
valid_format = 1;
break;
}
test_format = SDL_NextAudioFormat();
} }
/* Set up the notify structures */ if (!valid_format) {
for (i = 0; i < NUM_BUFFERS; ++i) { DSOUND_CloseDevice(this);
notify_positions[i].dwOffset = i * mixlen; SDL_SetError("DirectSound: Unsupported audio format");
notify_positions[i].hEventNotify = audio_event; return 0;
}
result = IDirectSoundNotify_SetNotificationPositions(notify,
NUM_BUFFERS,
notify_positions);
if (result == DS_OK) {
retval = 0;
}
done:
if (notify != NULL) {
IDirectSoundNotify_Release(notify);
} }
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)); SDL_memset(&waveformat, 0, sizeof(waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
/* Determine the audio parameters from the AudioSpec */ waveformat.nChannels = this->spec.channels;
switch (SDL_AUDIO_BITSIZE(spec->format)) { waveformat.nSamplesPerSec = this->spec.freq;
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.nBlockAlign = waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8); waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec = waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign; waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Update the fragment size as size in bytes */ /* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec); SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */ /* Open the audio device */
result = DSoundCreate(NULL, &sound, NULL); result = DSoundCreate(NULL, &this->hidden->sound, NULL);
if (result != DS_OK) { if (result != DS_OK) {
DSOUND_CloseDevice(this);
SetDSerror("DirectSoundCreate", result); SetDSerror("DirectSoundCreate", result);
return (-1); return 0;
} }
/* Create the audio buffer to which we write */ /* Create the audio buffer to which we write */
NUM_BUFFERS = -1; this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
#ifdef USE_PRIMARY_BUFFER if (this->hidden->num_buffers < 0) {
if (mainwin) { DSOUND_CloseDevice(this);
NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf, return 0;
&waveformat, spec->size);
} }
#endif /* USE_PRIMARY_BUFFER */
if (NUM_BUFFERS < 0) { /* The buffer will auto-start playing in DSOUND_WaitDevice() */
NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf, this->hidden->mixlen = this->spec.size;
&waveformat, spec->size);
if (NUM_BUFFERS < 0) { return 1; /* good to go. */
return (-1); }
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 if (!DSOUND_Load()) {
/* See if we can use DirectX 6 event notification */ return 0;
if (CreateAudioEvent(this) == 0) {
this->WaitAudio = DX6_WaitAudio_EventWait;
} else {
this->WaitAudio = DX5_WaitAudio_BusyWait;
} }
#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: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
*/ */
#include "SDL_config.h" #include "SDL_config.h"
#ifndef _SDL_lowaudio_h #ifndef _SDL_dx5audio_h
#define _SDL_lowaudio_h #define _SDL_dx5audio_h
#include "directx.h" #include "directx.h"
#include "../SDL_sysaudio.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 _THIS SDL_AudioDevice *this
/* The DirectSound objects */ /* The DirectSound objects */
...@@ -36,23 +36,12 @@ struct SDL_PrivateAudioData ...@@ -36,23 +36,12 @@ struct SDL_PrivateAudioData
{ {
LPDIRECTSOUND sound; LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf; LPDIRECTSOUNDBUFFER mixbuf;
int NUM_BUFFERS; int num_buffers;
int mixlen, silence; int mixlen;
DWORD lastchunk; DWORD lastchunk;
Uint8 *locked_buf; Uint8 *locked_buf;
HANDLE audio_event;
}; };
/* Old variable names */ #endif /* _SDL_dx5audio_h */
#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 */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
...@@ -165,7 +165,7 @@ SDL_GetMouseFocusWindow() ...@@ -165,7 +165,7 @@ SDL_GetMouseFocusWindow()
return mouse->focus; return mouse->focus;
} }
static int static int SDLCALL
FlushMouseMotion(void *param, SDL_Event * event) FlushMouseMotion(void *param, SDL_Event * event)
{ {
if (event->type == SDL_MOUSEMOTION if (event->type == SDL_MOUSEMOTION
......
...@@ -65,24 +65,28 @@ SDL_GetTicks(void) ...@@ -65,24 +65,28 @@ SDL_GetTicks(void)
*/ */
/* inline asm to avoid runtime inclusion */ /* inline asm to avoid runtime inclusion */
_asm { _asm {
push edx push edx
push eax push eax
mov eax, dword ptr hires_now mov eax, dword ptr hires_now
mov edx, dword ptr hires_now + 4 mov edx, dword ptr hires_now + 4
sub eax, dword ptr hires_start_ticks sub eax, dword ptr hires_start_ticks
sbb edx, dword ptr hires_start_ticks + 4 sbb edx, dword ptr hires_start_ticks + 4
mov ebx, 1000 mov ebx, 1000
mov ecx, edx mov ecx, edx
mul ebx mul ebx
push eax push eax
push edx push edx
mov eax, ecx mov eax, ecx
mul ebx mul ebx
pop eax pop eax
add edx, eax add edx, eax
pop eax pop eax
mov ebx, dword ptr hires_ticks_per_second mov ebx, dword ptr hires_ticks_per_second
div ebx mov dword ptr ticks, eax pop edx pop eax} div ebx
mov dword ptr ticks, eax
pop edx
pop eax
}
return ticks; return ticks;
...@@ -178,7 +182,7 @@ SDL_Delay(Uint32 ms) ...@@ -178,7 +182,7 @@ SDL_Delay(Uint32 ms)
static int timer_alive = 0; static int timer_alive = 0;
static SDL_Thread *timer = NULL; static SDL_Thread *timer = NULL;
static int static int SDLCALL
RunTimer(void *unused) RunTimer(void *unused)
{ {
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
#define SDL_RENDERCOPY_NEAREST 0x0100 #define SDL_RENDERCOPY_NEAREST 0x0100
typedef struct { typedef struct {
void *src; Uint8 *src;
int src_w, src_h; int src_w, src_h;
int src_pitch; int src_pitch;
void *dst; Uint8 *dst;
int dst_w, dst_h; int dst_w, dst_h;
int dst_pitch; int dst_pitch;
void *aux_data; void *aux_data;
...@@ -44,7 +44,7 @@ typedef struct { ...@@ -44,7 +44,7 @@ typedef struct {
Uint8 r, g, b, a; Uint8 r, g, b, a;
} SDL_RenderCopyData; } 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); extern SDL_RenderCopyFunc SDLCALL SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode);
......
...@@ -7,7 +7,7 @@ EXE = @EXE@ ...@@ -7,7 +7,7 @@ EXE = @EXE@
CFLAGS = @CFLAGS@ CFLAGS = @CFLAGS@
LIBS = @LIBS@ 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) all: Makefile $(TARGETS)
...@@ -23,6 +23,12 @@ graywin$(EXE): $(srcdir)/graywin.c ...@@ -23,6 +23,12 @@ graywin$(EXE): $(srcdir)/graywin.c
loopwave$(EXE): $(srcdir)/loopwave.c loopwave$(EXE): $(srcdir)/loopwave.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS) $(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 testalpha$(EXE): $(srcdir)/testalpha.c
$(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@ $(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@
......
...@@ -69,26 +69,12 @@ main(int argc, char *argv[]) ...@@ -69,26 +69,12 @@ main(int argc, char *argv[])
{ {
int i, n; 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 */ /* Load the SDL library */
if (SDL_Init(SDL_INIT_AUDIO) < 0) { if (SDL_Init(SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1); return (1);
} }
if (argv[1] == NULL) { if (argv[1] == NULL) {
argv[1] = "sample.wav"; argv[1] = "sample.wav";
} }
...@@ -120,7 +106,6 @@ main(int argc, char *argv[]) ...@@ -120,7 +106,6 @@ main(int argc, char *argv[])
SDL_PauseAudio(0); SDL_PauseAudio(0);
/* Let the audio run */ /* Let the audio run */
printf("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING))
SDL_Delay(1000); 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