mirror of
https://github.com/yawut/SDL.git
synced 2026-09-07 00:25:37 -05:00
Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
This commit is contained in:
46
configure.in
46
configure.in
@@ -511,9 +511,17 @@ CheckNAS()
|
||||
AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
|
||||
, enable_nas=yes)
|
||||
if test x$enable_audio = xyes -a x$enable_nas = xyes; then
|
||||
AC_CHECK_HEADER(audio/audiolib.h, have_nas_hdr=yes)
|
||||
AC_CHECK_LIB(audio, AuOpenServer, have_nas_lib=yes)
|
||||
|
||||
AC_MSG_CHECKING(for NAS audio support)
|
||||
have_nas=no
|
||||
if test -r /usr/X11R6/include/audio/audiolib.h; then
|
||||
|
||||
if test x$have_nas_hdr = xyes -a x$have_nas_lib = xyes; then
|
||||
have_nas=yes
|
||||
NAS_LIBS="-laudio"
|
||||
|
||||
elif test -r /usr/X11R6/include/audio/audiolib.h; then
|
||||
have_nas=yes
|
||||
NAS_CFLAGS="-I/usr/X11R6/include/"
|
||||
NAS_LIBS="-L/usr/X11R6/lib -laudio -lXt"
|
||||
@@ -525,12 +533,40 @@ AC_HELP_STRING([--enable-nas], [support the NAS audio API [[default=yes]]]),
|
||||
have_nas=yes
|
||||
NAS_LIBS="-lnas -lXt"
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT($have_nas)
|
||||
|
||||
if test x$have_nas = xyes; then
|
||||
AC_ARG_ENABLE(nas-shared,
|
||||
AC_HELP_STRING([--enable-nas-shared], [dynamically load NAS audio support [[default=yes]]]),
|
||||
, enable_nas_shared=yes)
|
||||
if test "x`echo $NAS_LIBS | grep -- -L`" = "x"; then
|
||||
if test "x`ls /lib/libaudio.so.* 2> /dev/null`" != "x"; then
|
||||
NAS_LIBS="-L/lib $NAS_LIBS"
|
||||
elif test "x`ls /usr/lib/libaudio.so.* 2> /dev/null`" != "x"; then
|
||||
NAS_LIBS="-L/usr/lib $NAS_LIBS"
|
||||
elif test "x`ls /usr/local/lib/libaudio.so.* 2> /dev/null`" != "x"; then
|
||||
NAS_LIBS="-L/usr/local/lib $NAS_LIBS"
|
||||
fi
|
||||
fi
|
||||
nas_lib_spec=`echo $NAS_LIBS | sed 's/.*-L\([[^ ]]*\).*/\1\/libaudio.so.*/'`
|
||||
nas_lib=`ls -- $nas_lib_spec | sed 's/.*\/\(.*\)/\1/; q'`
|
||||
echo "-- $nas_lib_spec -> $nas_lib"
|
||||
|
||||
if test x$have_loadso != xyes && \
|
||||
test x$enable_nas_shared = xyes; then
|
||||
AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic NAS loading])
|
||||
fi
|
||||
if test x$have_loadso = xyes && \
|
||||
test x$enable_nas_shared = xyes && test x$alsa_lib != x; then
|
||||
AC_DEFINE_UNQUOTED(SDL_AUDIO_DRIVER_NAS_DYNAMIC, "$nas_lib")
|
||||
else
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
|
||||
fi
|
||||
|
||||
AC_DEFINE(SDL_AUDIO_DRIVER_NAS)
|
||||
SOURCES="$SOURCES $srcdir/src/audio/nas/*.c"
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS $NAS_CFLAGS"
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $NAS_LIBS"
|
||||
have_audio=yes
|
||||
fi
|
||||
fi
|
||||
@@ -2006,7 +2042,7 @@ case "$host" in
|
||||
have_audio=yes
|
||||
;;
|
||||
aix)
|
||||
AC_DEFINE(SDL_AUDIO_DRIVER_PAUD)
|
||||
AC_DEFINE(SDL_AUDIO_DRIVER_PAUDIO)
|
||||
SOURCES="$SOURCES $srcdir/src/audio/paudio/*.c"
|
||||
have_audio=yes
|
||||
;;
|
||||
@@ -2206,7 +2242,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||
CheckBeGL
|
||||
# Set up files for the audio library
|
||||
if test x$enable_audio = xyes; then
|
||||
AC_DEFINE(SDL_AUDIO_DRIVER_BAUDIO)
|
||||
AC_DEFINE(SDL_AUDIO_DRIVER_BEOSAUDIO)
|
||||
SOURCES="$SOURCES $srcdir/src/audio/baudio/*.cc"
|
||||
have_audio=yes
|
||||
fi
|
||||
@@ -2323,7 +2359,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
|
||||
# If either the audio or CD driver is used, add the AudioUnit framework
|
||||
if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -framework,AudioToolbox -Wl,-framework,AudioUnit"
|
||||
fi
|
||||
;;
|
||||
*-*-mint*)
|
||||
|
||||
@@ -153,7 +153,7 @@ typedef struct SDL_AudioCVT
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/* These functions return the list of built in video drivers, in the
|
||||
/* These functions return the list of built in audio drivers, in the
|
||||
* order that they are normally initialized by default.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
|
||||
@@ -212,7 +212,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
|
||||
* may modify the requested size of the audio buffer, you should allocate
|
||||
* any local mixing buffers after you open the audio device.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
|
||||
extern DECLSPEC int SDLCALL SDL_OpenAudio(const SDL_AudioSpec * desired,
|
||||
SDL_AudioSpec * obtained);
|
||||
|
||||
/*
|
||||
@@ -228,6 +228,13 @@ typedef Uint32 SDL_AudioDeviceID;
|
||||
/*
|
||||
* Get the number of available devices exposed by the current driver.
|
||||
* Only valid after a successfully initializing the audio subsystem.
|
||||
* Returns -1 if an explicit list of devices can't be determined; this is
|
||||
* not an error. For example, if SDL is set up to talk to a remote audio
|
||||
* server, it can't list every one available on the Internet, but it will
|
||||
* still allow a specific host to be specified to SDL_OpenAudioDevice().
|
||||
* In many common cases, when this function returns a value <= 0, it can still
|
||||
* successfully open the default device (NULL for first argument of
|
||||
* SDL_OpenAudioDevice()).
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
|
||||
|
||||
@@ -235,15 +242,28 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
|
||||
* Get the human-readable name of a specific audio device.
|
||||
* Must be a value between 0 and (number of audio devices-1).
|
||||
* Only valid after a successfully initializing the audio subsystem.
|
||||
* The values returned by this function reflect the latest call to
|
||||
* SDL_GetNumAudioDevices(); recall that function to redetect available
|
||||
* hardware.
|
||||
*
|
||||
* The string returned by this function is UTF-8 encoded, read-only, and
|
||||
* managed internally. You are not to free it. If you need to keep the
|
||||
* string for any length of time, you should make your own copy of it, as it
|
||||
* will be invalid next time any of several other SDL functions is called.
|
||||
*/
|
||||
extern DECLSPEC const char *SDLCALL SDL_GetAudioDevice(int index,
|
||||
int iscapture);
|
||||
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
|
||||
int iscapture);
|
||||
|
||||
|
||||
/*
|
||||
* Open a specific audio device. Passing in a device name of NULL is
|
||||
* equivalent to SDL_OpenAudio(). Returns 0 on error, a valid device ID
|
||||
* on success.
|
||||
* Open a specific audio device. Passing in a device name of NULL requests
|
||||
* the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
|
||||
* The device name is a UTF-8 string reported by SDL_GetAudioDevice(), but
|
||||
* some drivers allow arbitrary and driver-specific strings, such as a
|
||||
* hostname/IP address for a remote audio server, or a filename in the
|
||||
* diskaudio driver.
|
||||
* Returns 0 on error, a valid device ID that is >= 2 on success.
|
||||
* SDL_OpenAudio(), unlike this function, always acts on device ID 1.
|
||||
*/
|
||||
extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
|
||||
*device,
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
|
||||
#undef SDL_AUDIO_DRIVER_ARTS
|
||||
#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
|
||||
#undef SDL_AUDIO_DRIVER_BAUDIO
|
||||
#undef SDL_AUDIO_DRIVER_BEOSAUDIO
|
||||
#undef SDL_AUDIO_DRIVER_BSD
|
||||
#undef SDL_AUDIO_DRIVER_COREAUDIO
|
||||
#undef SDL_AUDIO_DRIVER_DART
|
||||
@@ -168,9 +168,10 @@
|
||||
#undef SDL_AUDIO_DRIVER_MINT
|
||||
#undef SDL_AUDIO_DRIVER_MMEAUDIO
|
||||
#undef SDL_AUDIO_DRIVER_NAS
|
||||
#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
|
||||
#undef SDL_AUDIO_DRIVER_OSS
|
||||
#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
|
||||
#undef SDL_AUDIO_DRIVER_PAUD
|
||||
#undef SDL_AUDIO_DRIVER_PAUDIO
|
||||
#undef SDL_AUDIO_DRIVER_QNXNTO
|
||||
#undef SDL_AUDIO_DRIVER_SNDMGR
|
||||
#undef SDL_AUDIO_DRIVER_SUNAUDIO
|
||||
|
||||
@@ -91,7 +91,7 @@ typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
|
||||
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
|
||||
#endif
|
||||
|
||||
extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (*fn) (void *),
|
||||
extern DECLSPEC SDL_Thread *SDLCALL SDL_CreateThread(int (SDLCALL * f) (void *),
|
||||
void *data,
|
||||
pfnSDL_CurrentBeginThread
|
||||
pfnBeginThread,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
/* Routine to get the thread-specific error variable */
|
||||
#if SDL_THREADS_DISABLED
|
||||
/* !!! FIXME: what does this comment mean? Victim of Search and Replace? */
|
||||
/* The SDL_arraysize(The ),default (non-thread-safe) global error variable */
|
||||
static SDL_error SDL_global_error;
|
||||
#define SDL_GetErrBuf() (&SDL_global_error)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -159,21 +159,19 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||
float *dst = (float *) cvt->buf;
|
||||
if (SDL_AUDIO_ISBIGENDIAN(format)) {
|
||||
for (i = cvt->len_cvt / 8; i; --i, src += 2) {
|
||||
float src1, src2;
|
||||
src1 = SDL_SwapFloatBE(src[0]);
|
||||
src2 = SDL_SwapFloatBE(src[1]);
|
||||
const float src1 = SDL_SwapFloatBE(src[0]);
|
||||
const float src2 = SDL_SwapFloatBE(src[1]);
|
||||
const double added = ((double) src1) + ((double) src2);
|
||||
src1 = (float) (added * 0.5);
|
||||
*(dst++) = SDL_SwapFloatBE(src1);
|
||||
const float halved = (float) (added * 0.5);
|
||||
*(dst++) = SDL_SwapFloatBE(halved);
|
||||
}
|
||||
} else {
|
||||
for (i = cvt->len_cvt / 8; i; --i, src += 2) {
|
||||
float src1, src2;
|
||||
src1 = SDL_SwapFloatLE(src[0]);
|
||||
src2 = SDL_SwapFloatLE(src[1]);
|
||||
const float src1 = SDL_SwapFloatLE(src[0]);
|
||||
const float src2 = SDL_SwapFloatLE(src[1]);
|
||||
const double added = ((double) src1) + ((double) src2);
|
||||
src1 = (float) (added * 0.5);
|
||||
*(dst++) = SDL_SwapFloatLE(src1);
|
||||
const float halved = (float) (added * 0.5);
|
||||
*(dst++) = SDL_SwapFloatLE(halved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,14 +46,63 @@
|
||||
#define _PATH_DEV_AUDIO "/dev/audio"
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
test_device(const char *fname, int flags, int (*test)(int fd),
|
||||
char ***devices, int *devCount)
|
||||
{
|
||||
struct stat sb;
|
||||
if ( (stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode)) ) {
|
||||
int audio_fd = open(fname, flags, 0);
|
||||
if ( (audio_fd >= 0) && (test(audio_fd)) ) {
|
||||
void *p = SDL_realloc(*devices, ((*devCount)+1) * sizeof (char *));
|
||||
if (p != NULL) {
|
||||
size_t len = strlen(fname) + 1;
|
||||
char *str = (char *) SDL_malloc(len);
|
||||
*devices = (char **) p;
|
||||
if (str != NULL) {
|
||||
SDL_strlcpy(str, fname, len);
|
||||
(*devices)[(*devCount)++] = str;
|
||||
}
|
||||
}
|
||||
close(audio_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
|
||||
void
|
||||
SDL_FreeUnixAudioDevices(char ***devices, int *devCount)
|
||||
{
|
||||
int i = *devCount;
|
||||
if ((i > 0) && (*devices != NULL)) {
|
||||
while (i--) {
|
||||
SDL_free( (*devices)[*devCount] );
|
||||
}
|
||||
}
|
||||
|
||||
if (*devices != NULL) {
|
||||
SDL_free(*devices);
|
||||
}
|
||||
|
||||
*devices = NULL;
|
||||
*devCount = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_stub(int fd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
|
||||
char ***devices, int *devCount)
|
||||
{
|
||||
const char *audiodev;
|
||||
int audio_fd;
|
||||
char audiopath[1024];
|
||||
|
||||
if (test == NULL)
|
||||
test = test_stub;
|
||||
|
||||
/* Figure out what our audio device is */
|
||||
if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
|
||||
((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
|
||||
@@ -72,111 +121,16 @@ SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
|
||||
}
|
||||
}
|
||||
}
|
||||
audio_fd = open(audiodev, flags, 0);
|
||||
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;
|
||||
do { /* Don't use errno ENOENT - it may not be thread-safe */
|
||||
if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
|
||||
int instance = 0;
|
||||
while (instance++ <= 64) {
|
||||
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
|
||||
"%s%d", audiodev, instance++);
|
||||
exists = 0;
|
||||
if (stat(audiopath, &sb) == 0) {
|
||||
exists = 1;
|
||||
audio_fd = open(audiopath, flags, 0);
|
||||
}
|
||||
}
|
||||
while (exists && (audio_fd < 0));
|
||||
audiodev = audiopath;
|
||||
}
|
||||
if (path != NULL) {
|
||||
SDL_strlcpy(path, audiodev, maxlen);
|
||||
path[maxlen - 1] = '\0';
|
||||
}
|
||||
return (audio_fd);
|
||||
}
|
||||
|
||||
#elif SDL_AUDIO_DRIVER_PAUD
|
||||
|
||||
/* Get the name of the audio device we use for output */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_audiodev_c.h"
|
||||
|
||||
#ifndef _PATH_DEV_DSP
|
||||
#define _PATH_DEV_DSP "/dev/%caud%c/%c"
|
||||
#endif
|
||||
|
||||
char devsettings[][3] = {
|
||||
{'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
|
||||
{'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
|
||||
{'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
|
||||
{'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
|
||||
{'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
|
||||
{'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
|
||||
{'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
|
||||
{'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
|
||||
{'\0', '\0', '\0'}
|
||||
};
|
||||
|
||||
static int
|
||||
OpenUserDefinedDevice(char *path, int maxlen, int flags)
|
||||
{
|
||||
const char *audiodev;
|
||||
int audio_fd;
|
||||
|
||||
/* Figure out what our audio device is */
|
||||
if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
|
||||
audiodev = SDL_getenv("AUDIODEV");
|
||||
}
|
||||
if (audiodev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
audio_fd = open(audiodev, flags, 0);
|
||||
if (path != NULL) {
|
||||
SDL_strlcpy(path, audiodev, maxlen);
|
||||
path[maxlen - 1] = '\0';
|
||||
}
|
||||
return audio_fd;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
|
||||
{
|
||||
struct stat sb;
|
||||
int audio_fd;
|
||||
char audiopath[1024];
|
||||
int cycle;
|
||||
|
||||
audio_fd = OpenUserDefinedDevice(path, maxlen, flags);
|
||||
if (audio_fd != -1) {
|
||||
return audio_fd;
|
||||
}
|
||||
|
||||
cycle = 0;
|
||||
while (devsettings[cycle][0] != '\0') {
|
||||
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
|
||||
_PATH_DEV_DSP,
|
||||
devsettings[cycle][0],
|
||||
devsettings[cycle][1], devsettings[cycle][2]);
|
||||
|
||||
if (stat(audiopath, &sb) == 0) {
|
||||
audio_fd = open(audiopath, flags, 0);
|
||||
if (audio_fd > 0) {
|
||||
if (path != NULL) {
|
||||
SDL_strlcpy(path, audiopath, maxlen);
|
||||
}
|
||||
return audio_fd;
|
||||
}
|
||||
"%s%d", audiodev, instance);
|
||||
test_device(audiopath, flags, test, devices, devCount);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* Audio driver selection */
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
/* Open the audio device, storing the pathname in 'path' */
|
||||
extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic);
|
||||
void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
|
||||
char ***devs, int *count);
|
||||
void SDL_FreeUnixAudioDevices(char ***devices, int *devCount);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -89,21 +89,6 @@ static const Uint8 mix8[] = {
|
||||
#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
|
||||
#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
|
||||
|
||||
void
|
||||
SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
|
||||
{
|
||||
/* Mix the user-level audio format */
|
||||
if (current_audio) {
|
||||
SDL_AudioFormat format;
|
||||
if (current_audio->convert.needed) {
|
||||
format = current_audio->convert.src_format;
|
||||
} else {
|
||||
format = current_audio->spec.format;
|
||||
}
|
||||
SDL_MixAudioFormat(dst, src, format, len, volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
|
||||
|
||||
@@ -29,13 +29,33 @@
|
||||
|
||||
/* The SDL audio driver */
|
||||
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||
|
||||
/* Define the SDL audio driver structure */
|
||||
#define _THIS SDL_AudioDevice *_this
|
||||
#ifndef _STATUS
|
||||
#define _STATUS SDL_status *status
|
||||
#endif
|
||||
struct SDL_AudioDevice
|
||||
|
||||
typedef struct SDL_AudioDriverImpl
|
||||
{
|
||||
int (*DetectDevices)(int iscapture);
|
||||
const char *(*GetDeviceName)(int index, int iscapture);
|
||||
int (*OpenDevice) (_THIS, const char *devname, int iscapture);
|
||||
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
|
||||
void (*WaitDevice) (_THIS);
|
||||
void (*PlayDevice) (_THIS);
|
||||
Uint8 *(*GetDeviceBuf) (_THIS);
|
||||
void (*WaitDone) (_THIS);
|
||||
void (*CloseDevice) (_THIS);
|
||||
void (*LockDevice) (_THIS);
|
||||
void (*UnlockDevice) (_THIS);
|
||||
void (*Deinitialize) (void);
|
||||
|
||||
/* Some flags to push duplicate code into the core and reduce #ifdefs. */
|
||||
int ProvidesOwnCallbackThread:1;
|
||||
int SkipMixerLock:1;
|
||||
int HasCaptureSupport:1;
|
||||
int OnlyHasDefaultOutputDevice:1;
|
||||
int OnlyHasDefaultInputDevice:1;
|
||||
} SDL_AudioDriverImpl;
|
||||
|
||||
|
||||
typedef struct SDL_AudioDriver
|
||||
{
|
||||
/* * * */
|
||||
/* The name of this audio driver */
|
||||
@@ -45,21 +65,13 @@ struct SDL_AudioDevice
|
||||
/* The description of this audio driver */
|
||||
const char *desc;
|
||||
|
||||
/* * * */
|
||||
/* Public driver functions */
|
||||
int (*OpenAudio) (_THIS, SDL_AudioSpec * spec);
|
||||
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
|
||||
void (*WaitAudio) (_THIS);
|
||||
void (*PlayAudio) (_THIS);
|
||||
Uint8 *(*GetAudioBuf) (_THIS);
|
||||
void (*WaitDone) (_THIS);
|
||||
void (*CloseAudio) (_THIS);
|
||||
SDL_AudioDriverImpl impl;
|
||||
} SDL_AudioDriver;
|
||||
|
||||
/* * * */
|
||||
/* Lock / Unlock functions added for the Mac port */
|
||||
void (*LockAudio) (_THIS);
|
||||
void (*UnlockAudio) (_THIS);
|
||||
|
||||
/* Define the SDL audio driver structure */
|
||||
struct SDL_AudioDevice
|
||||
{
|
||||
/* * * */
|
||||
/* Data common to all devices */
|
||||
|
||||
@@ -70,6 +82,7 @@ struct SDL_AudioDevice
|
||||
SDL_AudioCVT convert;
|
||||
|
||||
/* Current state flags */
|
||||
int iscapture;
|
||||
int enabled;
|
||||
int paused;
|
||||
int opened;
|
||||
@@ -87,10 +100,6 @@ struct SDL_AudioDevice
|
||||
/* * * */
|
||||
/* Data private to this driver */
|
||||
struct SDL_PrivateAudioData *hidden;
|
||||
|
||||
/* * * */
|
||||
/* The function used to dispose of this structure */
|
||||
void (*free) (_THIS);
|
||||
};
|
||||
#undef _THIS
|
||||
|
||||
@@ -98,84 +107,10 @@ typedef struct AudioBootStrap
|
||||
{
|
||||
const char *name;
|
||||
const char *desc;
|
||||
int (*available) (void);
|
||||
SDL_AudioDevice *(*create) (int devindex);
|
||||
int (*init) (SDL_AudioDriverImpl *impl);
|
||||
int demand_only:1; /* 1==request explicitly, or it won't be available. */
|
||||
} AudioBootStrap;
|
||||
|
||||
#if SDL_AUDIO_DRIVER_BSD
|
||||
extern AudioBootStrap BSD_AUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_OSS
|
||||
extern AudioBootStrap DSP_bootstrap;
|
||||
extern AudioBootStrap DMA_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_ALSA
|
||||
extern AudioBootStrap ALSA_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_QNXNTO
|
||||
extern AudioBootStrap QNXNTOAUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_SUNAUDIO
|
||||
extern AudioBootStrap SUNAUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DMEDIA
|
||||
extern AudioBootStrap DMEDIA_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_ARTS
|
||||
extern AudioBootStrap ARTS_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_ESD
|
||||
extern AudioBootStrap ESD_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_NAS
|
||||
extern AudioBootStrap NAS_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DSOUND
|
||||
extern AudioBootStrap DSOUND_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_WAVEOUT
|
||||
extern AudioBootStrap WAVEOUT_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_PAUD
|
||||
extern AudioBootStrap Paud_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_BAUDIO
|
||||
extern AudioBootStrap BAUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_COREAUDIO
|
||||
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_SNDMGR
|
||||
extern AudioBootStrap SNDMGR_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_AHI
|
||||
extern AudioBootStrap AHI_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_MINT
|
||||
extern AudioBootStrap MINTAUDIO_GSXB_bootstrap;
|
||||
extern AudioBootStrap MINTAUDIO_MCSN_bootstrap;
|
||||
extern AudioBootStrap MINTAUDIO_STFA_bootstrap;
|
||||
extern AudioBootStrap MINTAUDIO_XBIOS_bootstrap;
|
||||
extern AudioBootStrap MINTAUDIO_DMA8_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DISK
|
||||
extern AudioBootStrap DISKAUD_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DUMMY
|
||||
extern AudioBootStrap DUMMYAUD_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DC
|
||||
extern AudioBootStrap DCAUD_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_MMEAUDIO
|
||||
extern AudioBootStrap MMEAUDIO_bootstrap;
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DART
|
||||
extern AudioBootStrap DART_bootstrap;
|
||||
#endif
|
||||
|
||||
/* This is the current audio device */
|
||||
extern SDL_AudioDevice *current_audio;
|
||||
|
||||
#endif /* _SDL_sysaudio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h> /* For kill() */
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
@@ -32,14 +35,6 @@
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_alsa_audio.h"
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
|
||||
#include <dlfcn.h>
|
||||
#include "SDL_name.h"
|
||||
#include "SDL_loadso.h"
|
||||
#else
|
||||
#define SDL_NAME(X) X
|
||||
#endif
|
||||
|
||||
|
||||
/* The tag name used by ALSA audio */
|
||||
#define DRIVER_NAME "alsa"
|
||||
@@ -47,182 +42,138 @@
|
||||
/* The default ALSA audio driver */
|
||||
#define DEFAULT_DEVICE "default"
|
||||
|
||||
/* Audio driver functions */
|
||||
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void ALSA_WaitAudio(_THIS);
|
||||
static void ALSA_PlayAudio(_THIS);
|
||||
static Uint8 *ALSA_GetAudioBuf(_THIS);
|
||||
static void ALSA_CloseAudio(_THIS);
|
||||
static int (*ALSA_snd_pcm_open)
|
||||
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
|
||||
static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm);
|
||||
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
|
||||
(snd_pcm_t *,const void *, snd_pcm_uframes_t);
|
||||
static int (*ALSA_snd_pcm_resume)(snd_pcm_t *);
|
||||
static int (*ALSA_snd_pcm_prepare)(snd_pcm_t *);
|
||||
static int (*ALSA_snd_pcm_drain)(snd_pcm_t *);
|
||||
static const char *(*ALSA_snd_strerror)(int);
|
||||
static size_t(*ALSA_snd_pcm_hw_params_sizeof)(void);
|
||||
static size_t(*ALSA_snd_pcm_sw_params_sizeof)(void);
|
||||
static int (*ALSA_snd_pcm_hw_params_any)(snd_pcm_t *, snd_pcm_hw_params_t *);
|
||||
static int (*ALSA_snd_pcm_hw_params_set_access)
|
||||
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
|
||||
static int (*ALSA_snd_pcm_hw_params_set_format)
|
||||
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
|
||||
static int (*ALSA_snd_pcm_hw_params_set_channels)
|
||||
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
|
||||
static int (*ALSA_snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *);
|
||||
static unsigned int (*ALSA_snd_pcm_hw_params_set_rate_near)
|
||||
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *);
|
||||
static snd_pcm_uframes_t (*ALSA_snd_pcm_hw_params_set_period_size_near)
|
||||
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t, int *);
|
||||
static snd_pcm_sframes_t (*ALSA_snd_pcm_hw_params_get_period_size)
|
||||
(const snd_pcm_hw_params_t *);
|
||||
static unsigned int (*ALSA_snd_pcm_hw_params_set_periods_near)
|
||||
(snd_pcm_t *,snd_pcm_hw_params_t *, unsigned int, int *);
|
||||
static int (*ALSA_snd_pcm_hw_params_get_periods)(snd_pcm_hw_params_t *);
|
||||
static int (*ALSA_snd_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *);
|
||||
static int (*ALSA_snd_pcm_sw_params_current)(snd_pcm_t*, snd_pcm_sw_params_t*);
|
||||
static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
|
||||
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
|
||||
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
|
||||
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
|
||||
static int (*ALSA_snd_pcm_sw_params)(snd_pcm_t *, snd_pcm_sw_params_t *);
|
||||
static int (*ALSA_snd_pcm_nonblock)(snd_pcm_t *, int);
|
||||
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
|
||||
#define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
|
||||
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
|
||||
|
||||
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
|
||||
static void *alsa_handle = NULL;
|
||||
static int alsa_loaded = 0;
|
||||
|
||||
static int (*SDL_snd_pcm_open) (snd_pcm_t ** pcm, const char *name,
|
||||
snd_pcm_stream_t stream, int mode);
|
||||
static int (*SDL_NAME(snd_pcm_open)) (snd_pcm_t ** pcm, const char *name,
|
||||
snd_pcm_stream_t stream, int mode);
|
||||
static int (*SDL_NAME(snd_pcm_close)) (snd_pcm_t * pcm);
|
||||
static snd_pcm_sframes_t(*SDL_NAME(snd_pcm_writei)) (snd_pcm_t * pcm,
|
||||
const void *buffer,
|
||||
snd_pcm_uframes_t size);
|
||||
static int (*SDL_NAME(snd_pcm_resume)) (snd_pcm_t * pcm);
|
||||
static int (*SDL_NAME(snd_pcm_prepare)) (snd_pcm_t * pcm);
|
||||
static int (*SDL_NAME(snd_pcm_drain)) (snd_pcm_t * pcm);
|
||||
static const char *(*SDL_NAME(snd_strerror)) (int errnum);
|
||||
static size_t(*SDL_NAME(snd_pcm_hw_params_sizeof)) (void);
|
||||
static size_t(*SDL_NAME(snd_pcm_sw_params_sizeof)) (void);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_any)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t * params);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_set_access)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t *
|
||||
params,
|
||||
snd_pcm_access_t
|
||||
access);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_set_format)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t *
|
||||
params,
|
||||
snd_pcm_format_t val);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_set_channels)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t *
|
||||
params,
|
||||
unsigned int val);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_get_channels)) (const
|
||||
snd_pcm_hw_params_t *
|
||||
params);
|
||||
static unsigned int
|
||||
(*SDL_NAME(snd_pcm_hw_params_set_rate_near)) (snd_pcm_t *
|
||||
pcm,
|
||||
snd_pcm_hw_params_t
|
||||
* params,
|
||||
unsigned int val, int *dir);
|
||||
static snd_pcm_uframes_t
|
||||
(*SDL_NAME(snd_pcm_hw_params_set_period_size_near)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t
|
||||
* params,
|
||||
snd_pcm_uframes_t
|
||||
val, int *dir);
|
||||
static snd_pcm_sframes_t
|
||||
(*SDL_NAME(snd_pcm_hw_params_get_period_size)) (const
|
||||
snd_pcm_hw_params_t
|
||||
* params);
|
||||
static unsigned int
|
||||
(*SDL_NAME(snd_pcm_hw_params_set_periods_near)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t
|
||||
* params,
|
||||
unsigned int val,
|
||||
int *dir);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params_get_periods)) (snd_pcm_hw_params_t *
|
||||
params);
|
||||
static int (*SDL_NAME(snd_pcm_hw_params)) (snd_pcm_t * pcm,
|
||||
snd_pcm_hw_params_t * params);
|
||||
/*
|
||||
*/
|
||||
static int (*SDL_NAME(snd_pcm_sw_params_current)) (snd_pcm_t * pcm,
|
||||
snd_pcm_sw_params_t *
|
||||
swparams);
|
||||
static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold)) (snd_pcm_t *
|
||||
pcm,
|
||||
snd_pcm_sw_params_t
|
||||
* params,
|
||||
snd_pcm_uframes_t
|
||||
val);
|
||||
static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min)) (snd_pcm_t * pcm,
|
||||
snd_pcm_sw_params_t
|
||||
* params,
|
||||
snd_pcm_uframes_t
|
||||
val);
|
||||
static int (*SDL_NAME(snd_pcm_sw_params)) (snd_pcm_t * pcm,
|
||||
snd_pcm_sw_params_t * params);
|
||||
static int (*SDL_NAME(snd_pcm_nonblock)) (snd_pcm_t * pcm, int nonblock);
|
||||
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
|
||||
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
|
||||
static int
|
||||
load_alsa_sym(const char *fn, void **addr)
|
||||
{
|
||||
/*
|
||||
* !!! FIXME:
|
||||
* Eventually, this will deal with fallbacks, version changes, and
|
||||
* missing symbols we can workaround. But for now, it doesn't.
|
||||
*/
|
||||
|
||||
#if HAVE_DLVSYM
|
||||
*addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
|
||||
if (*addr == NULL)
|
||||
#endif
|
||||
{
|
||||
*addr = dlsym(alsa_handle, fn);
|
||||
if (*addr == NULL) {
|
||||
SDL_SetError("dlsym('%s') failed: %s", fn, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
|
||||
static struct
|
||||
#define SDL_ALSA_SYM(x) \
|
||||
if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
|
||||
#else
|
||||
#define SDL_ALSA_SYM(x) ALSA_##x = x
|
||||
#endif
|
||||
|
||||
static int load_alsa_syms(void)
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} alsa_functions[] = {
|
||||
{
|
||||
"snd_pcm_open", (void **) (char *) &SDL_NAME(snd_pcm_open)}, {
|
||||
"snd_pcm_close", (void **) (char *) &SDL_NAME(snd_pcm_close)}, {
|
||||
"snd_pcm_writei", (void **) (char *) &SDL_NAME(snd_pcm_writei)}, {
|
||||
"snd_pcm_resume", (void **) (char *) &SDL_NAME(snd_pcm_resume)}, {
|
||||
"snd_pcm_prepare", (void **) (char *) &SDL_NAME(snd_pcm_prepare)}, {
|
||||
"snd_pcm_drain", (void **) (char *) &SDL_NAME(snd_pcm_drain)}, {
|
||||
"snd_strerror", (void **) (char *) &SDL_NAME(snd_strerror)}, {
|
||||
"snd_pcm_hw_params_sizeof",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_sizeof)}, {
|
||||
"snd_pcm_sw_params_sizeof",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_sizeof)}, {
|
||||
"snd_pcm_hw_params_any",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_any)}, {
|
||||
"snd_pcm_hw_params_set_access",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_access)}, {
|
||||
"snd_pcm_hw_params_set_format",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_format)}, {
|
||||
"snd_pcm_hw_params_set_channels",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_channels)}, {
|
||||
"snd_pcm_hw_params_get_channels",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_channels)}, {
|
||||
"snd_pcm_hw_params_set_rate_near",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_rate_near)}, {
|
||||
"snd_pcm_hw_params_set_period_size_near", (void **) (char *)
|
||||
&SDL_NAME(snd_pcm_hw_params_set_period_size_near)}, {
|
||||
"snd_pcm_hw_params_get_period_size",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_period_size)},
|
||||
{
|
||||
"snd_pcm_hw_params_set_periods_near", (void **) (char *)
|
||||
&SDL_NAME(snd_pcm_hw_params_set_periods_near)}, {
|
||||
"snd_pcm_hw_params_get_periods",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_periods)}, {
|
||||
"snd_pcm_hw_params", (void **) (char *) &SDL_NAME(snd_pcm_hw_params)}, {
|
||||
"snd_pcm_sw_params_current",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_current)}, {
|
||||
"snd_pcm_sw_params_set_start_threshold", (void **) (char *)
|
||||
&SDL_NAME(snd_pcm_sw_params_set_start_threshold)}, {
|
||||
"snd_pcm_sw_params_set_avail_min",
|
||||
(void **) (char *) &SDL_NAME(snd_pcm_sw_params_set_avail_min)}, {
|
||||
"snd_pcm_sw_params", (void **) (char *) &SDL_NAME(snd_pcm_sw_params)}, {
|
||||
"snd_pcm_nonblock", (void **) (char *) &SDL_NAME(snd_pcm_nonblock)},};
|
||||
SDL_ALSA_SYM(snd_pcm_open);
|
||||
SDL_ALSA_SYM(snd_pcm_close);
|
||||
SDL_ALSA_SYM(snd_pcm_writei);
|
||||
SDL_ALSA_SYM(snd_pcm_resume);
|
||||
SDL_ALSA_SYM(snd_pcm_prepare);
|
||||
SDL_ALSA_SYM(snd_pcm_drain);
|
||||
SDL_ALSA_SYM(snd_strerror);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
|
||||
SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_any);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
|
||||
SDL_ALSA_SYM(snd_pcm_hw_params);
|
||||
SDL_ALSA_SYM(snd_pcm_sw_params_current);
|
||||
SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
|
||||
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
|
||||
SDL_ALSA_SYM(snd_pcm_sw_params);
|
||||
SDL_ALSA_SYM(snd_pcm_nonblock);
|
||||
return 0;
|
||||
}
|
||||
#undef SDL_ALSA_SYM
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
|
||||
|
||||
static void
|
||||
UnloadALSALibrary(void)
|
||||
{
|
||||
if (alsa_loaded) {
|
||||
/* SDL_UnloadObject(alsa_handle);*/
|
||||
if (alsa_handle != NULL) {
|
||||
dlclose(alsa_handle);
|
||||
alsa_handle = NULL;
|
||||
alsa_loaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
LoadALSALibrary(void)
|
||||
{
|
||||
int i, retval = -1;
|
||||
|
||||
/* alsa_handle = SDL_LoadObject(alsa_library);*/
|
||||
alsa_handle = dlopen(alsa_library, RTLD_NOW);
|
||||
if (alsa_handle) {
|
||||
alsa_loaded = 1;
|
||||
retval = 0;
|
||||
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
|
||||
/* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/
|
||||
#if HAVE_DLVSYM
|
||||
*alsa_functions[i].func =
|
||||
dlvsym(alsa_handle, alsa_functions[i].name, "ALSA_0.9");
|
||||
if (!*alsa_functions[i].func)
|
||||
#endif
|
||||
*alsa_functions[i].func =
|
||||
dlsym(alsa_handle, alsa_functions[i].name);
|
||||
if (!*alsa_functions[i].func) {
|
||||
retval = -1;
|
||||
int retval = 0;
|
||||
if (alsa_handle == NULL) {
|
||||
alsa_handle = dlopen(alsa_library, RTLD_NOW);
|
||||
if (alsa_handle == NULL) {
|
||||
retval = -1;
|
||||
SDL_SetError("ALSA: dlopen('%s') failed: %s\n",
|
||||
alsa_library, strerror(errno));
|
||||
} else {
|
||||
retval = load_alsa_syms();
|
||||
if (retval < 0) {
|
||||
UnloadALSALibrary();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,12 +185,12 @@ LoadALSALibrary(void)
|
||||
static void
|
||||
UnloadALSALibrary(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
LoadALSALibrary(void)
|
||||
{
|
||||
load_alsa_syms();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -262,80 +213,10 @@ get_audio_device(int channels)
|
||||
return device;
|
||||
}
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
int available;
|
||||
int status;
|
||||
snd_pcm_t *handle;
|
||||
|
||||
available = 0;
|
||||
if (LoadALSALibrary() < 0) {
|
||||
return available;
|
||||
}
|
||||
status =
|
||||
SDL_NAME(snd_pcm_open) (&handle, get_audio_device(2),
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
if (status >= 0) {
|
||||
available = 1;
|
||||
SDL_NAME(snd_pcm_close) (handle);
|
||||
}
|
||||
UnloadALSALibrary();
|
||||
return (available);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
UnloadALSALibrary();
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
LoadALSALibrary();
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = ALSA_OpenAudio;
|
||||
this->WaitAudio = ALSA_WaitAudio;
|
||||
this->PlayAudio = ALSA_PlayAudio;
|
||||
this->GetAudioBuf = ALSA_GetAudioBuf;
|
||||
this->CloseAudio = ALSA_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap ALSA_bootstrap = {
|
||||
DRIVER_NAME, "ALSA 0.9 PCM audio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
ALSA_WaitAudio(_THIS)
|
||||
ALSA_WaitDevice(_THIS)
|
||||
{
|
||||
/* Check to see if the thread-parent process is still alive */
|
||||
{
|
||||
@@ -343,8 +224,9 @@ ALSA_WaitAudio(_THIS)
|
||||
/* Note that this only works with thread implementations
|
||||
that use a different process id for each thread.
|
||||
*/
|
||||
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
|
||||
if (kill(parent, 0) < 0) {
|
||||
/* Check every 10 loops */
|
||||
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
|
||||
if (kill(this->hidden->parent, 0) < 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
}
|
||||
@@ -352,13 +234,14 @@ ALSA_WaitAudio(_THIS)
|
||||
}
|
||||
|
||||
|
||||
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
|
||||
/*
|
||||
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
|
||||
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
|
||||
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
|
||||
*/
|
||||
#define SWIZ6(T) \
|
||||
T *ptr = (T *) mixbuf; \
|
||||
T *ptr = (T *) this->hidden->mixbuf; \
|
||||
const Uint32 count = (this->spec.samples / 6); \
|
||||
Uint32 i; \
|
||||
for (i = 0; i < count; i++, ptr += 6) { \
|
||||
@@ -392,8 +275,8 @@ swizzle_alsa_channels_6_8bit(_THIS)
|
||||
|
||||
|
||||
/*
|
||||
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
|
||||
* from Windows/Mac order to the format alsalib will want.
|
||||
* Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
|
||||
* channels from Windows/Mac order to the format alsalib will want.
|
||||
*/
|
||||
static __inline__ void
|
||||
swizzle_alsa_channels(_THIS)
|
||||
@@ -415,7 +298,7 @@ swizzle_alsa_channels(_THIS)
|
||||
|
||||
|
||||
static void
|
||||
ALSA_PlayAudio(_THIS)
|
||||
ALSA_PlayDevice(_THIS)
|
||||
{
|
||||
int status;
|
||||
int sample_len;
|
||||
@@ -424,11 +307,12 @@ ALSA_PlayAudio(_THIS)
|
||||
swizzle_alsa_channels(this);
|
||||
|
||||
sample_len = this->spec.samples;
|
||||
sample_buf = (signed short *) mixbuf;
|
||||
sample_buf = (signed short *) this->hidden->mixbuf;
|
||||
|
||||
while (sample_len > 0) {
|
||||
status =
|
||||
SDL_NAME(snd_pcm_writei) (pcm_handle, sample_buf, sample_len);
|
||||
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
||||
sample_buf, sample_len);
|
||||
|
||||
if (status < 0) {
|
||||
if (status == -EAGAIN) {
|
||||
SDL_Delay(1);
|
||||
@@ -437,11 +321,11 @@ ALSA_PlayAudio(_THIS)
|
||||
if (status == -ESTRPIPE) {
|
||||
do {
|
||||
SDL_Delay(1);
|
||||
status = SDL_NAME(snd_pcm_resume) (pcm_handle);
|
||||
status = ALSA_snd_pcm_resume(this->hidden->pcm_handle);
|
||||
} while (status == -EAGAIN);
|
||||
}
|
||||
if (status < 0) {
|
||||
status = SDL_NAME(snd_pcm_prepare) (pcm_handle);
|
||||
status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle);
|
||||
}
|
||||
if (status < 0) {
|
||||
/* Hmm, not much we can do - abort */
|
||||
@@ -456,74 +340,89 @@ ALSA_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
ALSA_GetAudioBuf(_THIS)
|
||||
ALSA_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
ALSA_CloseAudio(_THIS)
|
||||
ALSA_CloseDevice(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (pcm_handle) {
|
||||
SDL_NAME(snd_pcm_drain) (pcm_handle);
|
||||
SDL_NAME(snd_pcm_close) (pcm_handle);
|
||||
pcm_handle = NULL;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->pcm_handle) {
|
||||
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
|
||||
ALSA_snd_pcm_close(this->hidden->pcm_handle);
|
||||
this->hidden->pcm_handle = NULL;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
int status;
|
||||
snd_pcm_hw_params_t *hwparams;
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_uframes_t frames;
|
||||
SDL_AudioFormat test_format;
|
||||
int status = 0;
|
||||
snd_pcm_t *pcm_handle = NULL;
|
||||
snd_pcm_hw_params_t *hwparams = NULL;
|
||||
snd_pcm_sw_params_t *swparams = NULL;
|
||||
snd_pcm_format_t format = 0;
|
||||
snd_pcm_uframes_t frames = 0;
|
||||
SDL_AudioFormat test_format = 0;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Open the audio device */
|
||||
/* Name of device should depend on # channels in spec */
|
||||
status =
|
||||
SDL_NAME(snd_pcm_open) (&pcm_handle,
|
||||
get_audio_device(spec->channels),
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
status = ALSA_snd_pcm_open(&pcm_handle,
|
||||
get_audio_device(this->spec.channels),
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't open audio device: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't open audio device: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->hidden->pcm_handle = pcm_handle;
|
||||
|
||||
/* Figure out what the hardware is capable of */
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
status = SDL_NAME(snd_pcm_hw_params_any) (pcm_handle, hwparams);
|
||||
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't get hardware config: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't get hardware config: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SDL only uses interleaved sample output */
|
||||
status =
|
||||
SDL_NAME(snd_pcm_hw_params_set_access) (pcm_handle, hwparams,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't set interleaved access: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't set interleaved access: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
status = -1;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
test_format && (status < 0);) {
|
||||
status = 0; /* if we can't support a format, it'll become -1. */
|
||||
status = 0; /* if we can't support a format, it'll become -1. */
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
format = SND_PCM_FORMAT_U8;
|
||||
@@ -560,131 +459,151 @@ ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
break;
|
||||
}
|
||||
if (status >= 0) {
|
||||
status =
|
||||
SDL_NAME(snd_pcm_hw_params_set_format) (pcm_handle,
|
||||
hwparams, format);
|
||||
status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
|
||||
hwparams, format);
|
||||
}
|
||||
if (status < 0) {
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
}
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't find any hardware audio formats");
|
||||
return 0;
|
||||
}
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
/* Set the number of channels */
|
||||
status =
|
||||
SDL_NAME(snd_pcm_hw_params_set_channels) (pcm_handle, hwparams,
|
||||
spec->channels);
|
||||
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
|
||||
this->spec.channels);
|
||||
if (status < 0) {
|
||||
status = SDL_NAME(snd_pcm_hw_params_get_channels) (hwparams);
|
||||
status = ALSA_snd_pcm_hw_params_get_channels(hwparams);
|
||||
if ((status <= 0) || (status > 2)) {
|
||||
SDL_SetError("Couldn't set audio channels");
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't set audio channels");
|
||||
return 0;
|
||||
}
|
||||
spec->channels = status;
|
||||
this->spec.channels = status;
|
||||
}
|
||||
|
||||
/* Set the audio rate */
|
||||
status =
|
||||
SDL_NAME(snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams,
|
||||
spec->freq, NULL);
|
||||
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
|
||||
this->spec.freq, NULL);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't set audio frequency: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't set audio frequency: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
spec->freq = status;
|
||||
this->spec.freq = status;
|
||||
|
||||
/* Set the buffer size, in samples */
|
||||
frames = spec->samples;
|
||||
frames =
|
||||
SDL_NAME(snd_pcm_hw_params_set_period_size_near) (pcm_handle,
|
||||
hwparams, frames,
|
||||
NULL);
|
||||
spec->samples = frames;
|
||||
SDL_NAME(snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2,
|
||||
NULL);
|
||||
frames = this->spec.samples;
|
||||
frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
|
||||
frames, NULL);
|
||||
this->spec.samples = frames;
|
||||
ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);
|
||||
|
||||
/* "set" the hardware with the desired parameters */
|
||||
status = SDL_NAME(snd_pcm_hw_params) (pcm_handle, hwparams);
|
||||
status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't set hardware audio parameters: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is useful for debugging... */
|
||||
/*
|
||||
{ snd_pcm_sframes_t bufsize; int fragments;
|
||||
bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams);
|
||||
fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams);
|
||||
|
||||
fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
|
||||
#if AUDIO_DEBUG
|
||||
{
|
||||
snd_pcm_sframes_t bufsize;
|
||||
int fragments;
|
||||
bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams);
|
||||
fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams);
|
||||
fprintf(stderr,"ALSA: bufsize = %ld, fragments = %d\n",bufsize,fragments);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* Set the software parameters */
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
status = SDL_NAME(snd_pcm_sw_params_current) (pcm_handle, swparams);
|
||||
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't get software config: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't get software config: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
status =
|
||||
SDL_NAME(snd_pcm_sw_params_set_start_threshold) (pcm_handle,
|
||||
swparams, 0);
|
||||
status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't set start threshold: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("ALSA: Couldn't set start threshold: %s",
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
status =
|
||||
SDL_NAME(snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams,
|
||||
frames);
|
||||
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
|
||||
if (status < 0) {
|
||||
SDL_SetError("Couldn't set avail min: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
status = SDL_NAME(snd_pcm_sw_params) (pcm_handle, swparams);
|
||||
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
|
||||
if (status < 0) {
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set software audio parameters: %s",
|
||||
SDL_NAME(snd_strerror) (status));
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
ALSA_snd_strerror(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
ALSA_CloseAudio(this);
|
||||
return (-1);
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
ALSA_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
this->hidden->parent = getpid();
|
||||
|
||||
/* Switch to blocking mode for playback */
|
||||
SDL_NAME(snd_pcm_nonblock) (pcm_handle, 0);
|
||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ALSA_Deinitialize(void)
|
||||
{
|
||||
UnloadALSALibrary();
|
||||
}
|
||||
|
||||
static int
|
||||
ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
if (LoadALSALibrary() < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = ALSA_OpenDevice;
|
||||
impl->WaitDevice = ALSA_WaitDevice;
|
||||
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
|
||||
impl->PlayDevice = ALSA_PlayDevice;
|
||||
impl->CloseDevice = ALSA_CloseDevice;
|
||||
impl->Deinitialize = ALSA_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap ALSA_bootstrap = {
|
||||
DRIVER_NAME, "ALSA 0.9 PCM audio", ALSA_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -46,11 +46,5 @@ struct SDL_PrivateAudioData
|
||||
int mixlen;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define pcm_handle (this->hidden->pcm_handle)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
|
||||
#endif /* _ALSA_PCM_audio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
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: */
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2006 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_ahiaudio_h
|
||||
#define _SDL_ahiaudio_h
|
||||
|
||||
#include <exec/exec.h>
|
||||
#include <dos/dos.h>
|
||||
#ifdef __SASC
|
||||
#include <proto/exec.h>
|
||||
#else
|
||||
#include <inline/exec.h>
|
||||
#endif
|
||||
|
||||
#include <devices/ahi.h>
|
||||
#include "mydebug.h"
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* The handle for the audio device */
|
||||
struct AHIRequest *audio_req[2];
|
||||
struct MsgPort *audio_port;
|
||||
Sint32 freq, type, bytespersample, size;
|
||||
Uint8 *mixbuf[2]; /* The app mixing buffer */
|
||||
int current_buffer;
|
||||
Uint32 playing;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_port (this->hidden->audio_port)
|
||||
#define audio_req (this->hidden->audio_req)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define current_buffer (this->hidden->current_buffer)
|
||||
#define playing (this->hidden->playing)
|
||||
|
||||
#endif /* _SDL_ahiaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_artsaudio.h"
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
|
||||
@@ -40,19 +39,12 @@
|
||||
/* The tag name used by artsc audio */
|
||||
#define ARTS_DRIVER_NAME "arts"
|
||||
|
||||
/* Audio driver functions */
|
||||
static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void ARTS_WaitAudio(_THIS);
|
||||
static void ARTS_PlayAudio(_THIS);
|
||||
static Uint8 *ARTS_GetAudioBuf(_THIS);
|
||||
static void ARTS_CloseAudio(_THIS);
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
|
||||
|
||||
static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
|
||||
static void *arts_handle = NULL;
|
||||
static int arts_loaded = 0;
|
||||
|
||||
/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
|
||||
static int (*SDL_NAME(arts_init)) (void);
|
||||
static void (*SDL_NAME(arts_free)) (void);
|
||||
static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
|
||||
@@ -65,28 +57,32 @@ static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
|
||||
static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
|
||||
int count);
|
||||
static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
|
||||
static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
|
||||
static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
|
||||
|
||||
#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} arts_functions[] = {
|
||||
{
|
||||
"arts_init", (void **) &SDL_NAME(arts_init)}, {
|
||||
"arts_free", (void **) &SDL_NAME(arts_free)}, {
|
||||
"arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, {
|
||||
"arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, {
|
||||
"arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, {
|
||||
"arts_write", (void **) &SDL_NAME(arts_write)}, {
|
||||
"arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},};
|
||||
SDL_ARTS_SYM(arts_init),
|
||||
SDL_ARTS_SYM(arts_free),
|
||||
SDL_ARTS_SYM(arts_play_stream),
|
||||
SDL_ARTS_SYM(arts_stream_set),
|
||||
SDL_ARTS_SYM(arts_stream_get),
|
||||
SDL_ARTS_SYM(arts_write),
|
||||
SDL_ARTS_SYM(arts_close_stream),
|
||||
SDL_ARTS_SYM(arts_error_text),
|
||||
};
|
||||
#undef SDL_ARTS_SYM
|
||||
|
||||
static void
|
||||
UnloadARTSLibrary()
|
||||
{
|
||||
if (arts_loaded) {
|
||||
if (arts_handle != NULL) {
|
||||
SDL_UnloadObject(arts_handle);
|
||||
arts_handle = NULL;
|
||||
arts_loaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,20 +91,22 @@ LoadARTSLibrary(void)
|
||||
{
|
||||
int i, retval = -1;
|
||||
|
||||
arts_handle = SDL_LoadObject(arts_library);
|
||||
if (arts_handle) {
|
||||
arts_loaded = 1;
|
||||
retval = 0;
|
||||
for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
|
||||
*arts_functions[i].func =
|
||||
SDL_LoadFunction(arts_handle, arts_functions[i].name);
|
||||
if (!*arts_functions[i].func) {
|
||||
retval = -1;
|
||||
UnloadARTSLibrary();
|
||||
break;
|
||||
if (arts_handle == NULL) {
|
||||
arts_handle = SDL_LoadObject(arts_library);
|
||||
if (arts_handle != NULL) {
|
||||
retval = 0;
|
||||
for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
|
||||
*arts_functions[i].func =
|
||||
SDL_LoadFunction(arts_handle, arts_functions[i].name);
|
||||
if (!*arts_functions[i].func) {
|
||||
retval = -1;
|
||||
UnloadARTSLibrary();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -128,117 +126,45 @@ LoadARTSLibrary(void)
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
int available = 0;
|
||||
|
||||
if (LoadARTSLibrary() < 0) {
|
||||
return available;
|
||||
}
|
||||
if (SDL_NAME(arts_init) () == 0) {
|
||||
#define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */
|
||||
#ifdef ARTS_CRASH_HACK
|
||||
arts_stream_t stream2;
|
||||
stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
|
||||
SDL_NAME(arts_write) (stream2, "", 0);
|
||||
SDL_NAME(arts_close_stream) (stream2);
|
||||
#endif
|
||||
available = 1;
|
||||
SDL_NAME(arts_free) ();
|
||||
}
|
||||
UnloadARTSLibrary();
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
UnloadARTSLibrary();
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
LoadARTSLibrary();
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
stream = 0;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = ARTS_OpenAudio;
|
||||
this->WaitAudio = ARTS_WaitAudio;
|
||||
this->PlayAudio = ARTS_PlayAudio;
|
||||
this->GetAudioBuf = ARTS_GetAudioBuf;
|
||||
this->CloseAudio = ARTS_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap ARTS_bootstrap = {
|
||||
ARTS_DRIVER_NAME, "Analog Realtime Synthesizer",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
ARTS_WaitAudio(_THIS)
|
||||
ARTS_WaitDevice(_THIS)
|
||||
{
|
||||
Sint32 ticks;
|
||||
|
||||
/* Check to see if the thread-parent process is still alive */
|
||||
{
|
||||
static int cnt = 0;
|
||||
/* Note that this only works with thread implementations
|
||||
/* Note that this only works with thread implementations
|
||||
that use a different process id for each thread.
|
||||
*/
|
||||
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
|
||||
if (kill(parent, 0) < 0) {
|
||||
/* Check every 10 loops */
|
||||
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
|
||||
if (kill(this->hidden->parent, 0) < 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use timer for general audio synchronization */
|
||||
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
|
||||
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
|
||||
if (ticks > 0) {
|
||||
SDL_Delay(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ARTS_PlayAudio(_THIS)
|
||||
ARTS_PlayDevice(_THIS)
|
||||
{
|
||||
int written;
|
||||
|
||||
/* Write the audio data */
|
||||
written = SDL_NAME(arts_write) (stream, mixbuf, mixlen);
|
||||
int written = SDL_NAME(arts_write) (
|
||||
this->hidden->stream,
|
||||
this->hidden->mixbuf,
|
||||
this->hidden->mixlen);
|
||||
|
||||
/* If timer synchronization is enabled, set the next write frame */
|
||||
if (frame_ticks) {
|
||||
next_frame += frame_ticks;
|
||||
if (this->hidden->frame_ticks) {
|
||||
this->hidden->next_frame += this->hidden->frame_ticks;
|
||||
}
|
||||
|
||||
/* If we couldn't write, assume fatal error for now */
|
||||
@@ -250,41 +176,57 @@ ARTS_PlayAudio(_THIS)
|
||||
#endif
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
ARTS_GetAudioBuf(_THIS)
|
||||
static void
|
||||
ARTS_WaitDone(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
/* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
|
||||
}
|
||||
|
||||
|
||||
static Uint8 *
|
||||
ARTS_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ARTS_CloseAudio(_THIS)
|
||||
ARTS_CloseDevice(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->stream) {
|
||||
SDL_NAME(arts_close_stream) (this->hidden->stream);
|
||||
this->hidden->stream = 0;
|
||||
}
|
||||
SDL_NAME(arts_free) ();
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
if (stream) {
|
||||
SDL_NAME(arts_close_stream) (stream);
|
||||
stream = 0;
|
||||
}
|
||||
SDL_NAME(arts_free) ();
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
int bits, frag_spec;
|
||||
SDL_AudioFormat test_format, format;
|
||||
int rc = 0;
|
||||
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 */
|
||||
format = 0;
|
||||
bits = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!format && test_format;) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
@@ -307,51 +249,108 @@ ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
}
|
||||
if (format == 0) {
|
||||
ARTS_CloseDevice(this);
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
if (SDL_NAME(arts_init) () != 0) {
|
||||
SDL_SetError("Unable to initialize ARTS");
|
||||
return (-1);
|
||||
if ((rc = SDL_NAME(arts_init) ()) != 0) {
|
||||
ARTS_CloseDevice(this);
|
||||
SDL_SetError( "Unable to initialize ARTS: %s",
|
||||
SDL_NAME(arts_error_text)(rc) );
|
||||
return 0;
|
||||
}
|
||||
stream =
|
||||
SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL");
|
||||
this->hidden->stream = SDL_NAME(arts_play_stream) (
|
||||
this->spec.freq,
|
||||
bits, this->spec.channels,
|
||||
"SDL");
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Determine the power of two of the fragment size */
|
||||
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec);
|
||||
if ((0x01 << frag_spec) != spec->size) {
|
||||
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
|
||||
if ((0x01 << frag_spec) != this->spec.size) {
|
||||
ARTS_CloseDevice(this);
|
||||
SDL_SetError("Fragment size must be a power of two");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
||||
|
||||
#ifdef ARTS_P_PACKET_SETTINGS
|
||||
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec);
|
||||
SDL_NAME(arts_stream_set) (this->hidden->stream,
|
||||
ARTS_P_PACKET_SETTINGS, frag_spec);
|
||||
#else
|
||||
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE,
|
||||
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
|
||||
frag_spec & 0xffff);
|
||||
SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16);
|
||||
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
|
||||
frag_spec >> 16);
|
||||
#endif
|
||||
spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE);
|
||||
this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
|
||||
ARTS_P_PACKET_SIZE);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
return (-1);
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
ARTS_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
this->hidden->parent = getpid();
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ARTS_Deinitialize(void)
|
||||
{
|
||||
UnloadARTSLibrary();
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ARTS_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
if (LoadARTSLibrary() < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
if (SDL_NAME(arts_init) () != 0) {
|
||||
UnloadARTSLibrary();
|
||||
SDL_SetError("ARTS: arts_init failed (no audio server?)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Play a stream so aRts doesn't crash */
|
||||
arts_stream_t stream;
|
||||
stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
|
||||
SDL_NAME(arts_write) (stream, "", 0);
|
||||
SDL_NAME(arts_close_stream) (stream);
|
||||
SDL_NAME(arts_free) ();
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = ARTS_OpenDevice;
|
||||
impl->PlayDevice = ARTS_PlayDevice;
|
||||
impl->WaitDevice = ARTS_WaitDevice;
|
||||
impl->GetDeviceBuf = ARTS_GetDeviceBuf;
|
||||
impl->CloseDevice = ARTS_CloseDevice;
|
||||
impl->WaitDone = ARTS_WaitDone;
|
||||
impl->Deinitialize = ARTS_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap ARTS_bootstrap = {
|
||||
ARTS_DRIVER_NAME, "Analog RealTime Synthesizer", ARTS_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -49,13 +49,5 @@ struct SDL_PrivateAudioData
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
#define stream (this->hidden->stream)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
|
||||
#endif /* _SDL_artscaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -36,138 +36,81 @@ extern "C"
|
||||
#include "../../thread/beos/SDL_systhread_c.h"
|
||||
#include "SDL_beaudio.h"
|
||||
|
||||
}
|
||||
|
||||
/* Audio driver functions */
|
||||
static int BE_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void BE_WaitAudio(_THIS);
|
||||
static void BE_PlayAudio(_THIS);
|
||||
static Uint8 *BE_GetAudioBuf(_THIS);
|
||||
static void BE_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int Audio_Available(void)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *device;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
device = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (device) {
|
||||
SDL_memset(device, 0, (sizeof *device));
|
||||
device->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *device->hidden));
|
||||
}
|
||||
if ((device == NULL) || (device->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (device) {
|
||||
SDL_free(device);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
device->OpenAudio = BE_OpenAudio;
|
||||
device->WaitAudio = BE_WaitAudio;
|
||||
device->PlayAudio = BE_PlayAudio;
|
||||
device->GetAudioBuf = BE_GetAudioBuf;
|
||||
device->CloseAudio = BE_CloseAudio;
|
||||
|
||||
device->free = Audio_DeleteDevice;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
AudioBootStrap BAUDIO_bootstrap = {
|
||||
"baudio", "BeOS BSoundPlayer",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
|
||||
/* The BeOS callback for handling the audio buffer */
|
||||
static void FillSound(void *device, void *stream, size_t len,
|
||||
const media_raw_audio_format & format)
|
||||
{
|
||||
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
||||
static void
|
||||
FillSound(void *device, void *stream, size_t len,
|
||||
const media_raw_audio_format & format)
|
||||
{
|
||||
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
||||
|
||||
/* Silence the buffer, since it's ours */
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
/* 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;
|
||||
/* Only do soemthing if audio is enabled */
|
||||
if (!audio->enabled)
|
||||
return;
|
||||
|
||||
if (!audio->paused) {
|
||||
if (audio->convert.needed) {
|
||||
SDL_mutexP(audio->mixer_lock);
|
||||
(*audio->spec.callback) (audio->spec.userdata,
|
||||
if (!audio->paused) {
|
||||
if (audio->convert.needed) {
|
||||
SDL_mutexP(audio->mixer_lock);
|
||||
(*audio->spec.callback) (audio->spec.userdata,
|
||||
(Uint8 *) audio->convert.buf,
|
||||
audio->convert.len);
|
||||
SDL_mutexV(audio->mixer_lock);
|
||||
SDL_ConvertAudio(&audio->convert);
|
||||
SDL_memcpy(stream, audio->convert.buf,
|
||||
audio->convert.len_cvt);
|
||||
} else {
|
||||
SDL_mutexP(audio->mixer_lock);
|
||||
(*audio->spec.callback) (audio->spec.userdata,
|
||||
(Uint8 *) stream, len);
|
||||
SDL_mutexV(audio->mixer_lock);
|
||||
}
|
||||
SDL_mutexV(audio->mixer_lock);
|
||||
SDL_ConvertAudio(&audio->convert);
|
||||
SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
|
||||
} else {
|
||||
SDL_mutexP(audio->mixer_lock);
|
||||
(*audio->spec.callback) (audio->spec.userdata,
|
||||
(Uint8 *) stream, len);
|
||||
SDL_mutexV(audio->mixer_lock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dummy functions -- we don't use thread-based audio */
|
||||
void BE_WaitAudio(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void BE_PlayAudio(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Uint8 *BE_GetAudioBuf(_THIS)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void BE_CloseAudio(_THIS)
|
||||
{
|
||||
if (audio_obj) {
|
||||
audio_obj->Stop();
|
||||
delete audio_obj;
|
||||
audio_obj = NULL;
|
||||
static void
|
||||
BEOSAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if (_this->hidden != NULL) {
|
||||
if (_this->hidden->audio_obj) {
|
||||
_this->hidden->audio_obj->Stop();
|
||||
delete _this->hidden->audio_obj;
|
||||
_this->hidden->audio_obj = NULL;
|
||||
}
|
||||
|
||||
/* Quit the Be Application, if there's nothing left to do */
|
||||
SDL_QuitBeApp();
|
||||
delete _this->hidden;
|
||||
_this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int BE_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
{
|
||||
int valid_datatype = 0;
|
||||
media_raw_audio_format format;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
static int
|
||||
BEOSAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
int valid_datatype = 0;
|
||||
media_raw_audio_format format;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
|
||||
|
||||
/* Parse the audio format and fill the Be raw audio format */
|
||||
memset(&format, '\0', sizeof(media_raw_audio_format));
|
||||
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
|
||||
format.frame_rate = (float) spec->freq;
|
||||
format.channel_count = spec->channels; /* !!! FIXME: support > 2? */
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
valid_datatype = 1;
|
||||
spec->format = test_format;
|
||||
switch (test_format) {
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
_this->hidden = new SDL_PrivateAudioData;
|
||||
if (_this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
|
||||
|
||||
/* Parse the audio format and fill the Be raw audio format */
|
||||
SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
|
||||
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
|
||||
format.frame_rate = (float) _this->spec.freq;
|
||||
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
valid_datatype = 1;
|
||||
_this->spec.format = test_format;
|
||||
switch (test_format) {
|
||||
case AUDIO_S8:
|
||||
format.format = media_raw_audio_format::B_AUDIO_CHAR;
|
||||
break;
|
||||
@@ -207,43 +150,67 @@ extern "C"
|
||||
valid_datatype = 0;
|
||||
test_format = SDL_NextAudioFormat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
format.buffer_size = spec->samples;
|
||||
|
||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Initialize the Be Application, if it's not already started */
|
||||
if (SDL_InitBeApp() < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
/* Subscribe to the audio stream (creates a new thread) */
|
||||
{
|
||||
sigset_t omask;
|
||||
SDL_MaskSignals(&omask);
|
||||
audio_obj = new BSoundPlayer(&format, "SDL Audio", FillSound,
|
||||
NULL, _this);
|
||||
SDL_UnmaskSignals(&omask);
|
||||
}
|
||||
if (audio_obj->Start() == B_NO_ERROR) {
|
||||
audio_obj->SetHasData(true);
|
||||
} else {
|
||||
SDL_SetError("Unable to start Be audio");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* We're running! */
|
||||
return (1);
|
||||
}
|
||||
|
||||
}; /* Extern C */
|
||||
format.buffer_size = _this->spec.samples;
|
||||
|
||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||
BEOSAUDIO_CloseDevice(_this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(&_this->spec);
|
||||
|
||||
/* Subscribe to the audio stream (creates a new thread) */
|
||||
sigset_t omask;
|
||||
SDL_MaskSignals(&omask);
|
||||
_this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
|
||||
FillSound, NULL, _this);
|
||||
SDL_UnmaskSignals(&omask);
|
||||
|
||||
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
|
||||
_this->hidden->audio_obj->SetHasData(true);
|
||||
} else {
|
||||
BEOSAUDIO_CloseDevice(_this);
|
||||
SDL_SetError("Unable to start Be audio");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We're running! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
BEOSAUDIO_Deinitialize(void)
|
||||
{
|
||||
SDL_QuitBeApp();
|
||||
}
|
||||
|
||||
static int
|
||||
BEOSAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Initialize the Be Application, if it's not already started */
|
||||
if (SDL_InitBeApp() < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = BEOSAUDIO_OpenDevice;
|
||||
impl->CloseDevice = BEOSAUDIO_CloseDevice;
|
||||
impl->Deinitialize = BEOSAUDIO_Deinitialize;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" { extern AudioBootStrap BEOSAUDIO_bootstrap; }
|
||||
AudioBootStrap BEOSAUDIO_bootstrap = {
|
||||
"baudio", "BeOS BSoundPlayer", BEOSAUDIO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_beaudio_h
|
||||
#define _SDL_beaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *_this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -34,8 +34,6 @@ struct SDL_PrivateAudioData
|
||||
BSoundPlayer *audio_obj;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_obj (_this->hidden->audio_obj)
|
||||
#endif /* _SDL_beaudio_h */
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -61,195 +61,91 @@
|
||||
/* #define DEBUG_AUDIO_STREAM */
|
||||
|
||||
#ifdef USE_BLOCKING_WRITES
|
||||
#define OPEN_FLAGS O_WRONLY
|
||||
#define OPEN_FLAGS_OUTPUT O_WRONLY
|
||||
#define OPEN_FLAGS_INPUT O_RDONLY
|
||||
#else
|
||||
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
|
||||
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
|
||||
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
|
||||
#endif
|
||||
|
||||
/* Audio driver functions */
|
||||
static void OBSD_WaitAudio(_THIS);
|
||||
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void OBSD_PlayAudio(_THIS);
|
||||
static Uint8 *OBSD_GetAudioBuf(_THIS);
|
||||
static void OBSD_CloseAudio(_THIS);
|
||||
/* !!! FIXME: so much cut and paste with dsp/dma drivers... */
|
||||
static char **outputDevices = NULL;
|
||||
static int outputDeviceCount = 0;
|
||||
static char **inputDevices = NULL;
|
||||
static int inputDeviceCount = 0;
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
static void OBSD_Status(_THIS);
|
||||
#endif
|
||||
static inline void
|
||||
free_device_list(char ***devs, int *count)
|
||||
{
|
||||
SDL_FreeUnixAudioDevices(devs, count);
|
||||
}
|
||||
|
||||
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 inline void
|
||||
build_device_lists(void)
|
||||
{
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
free_device_lists(void)
|
||||
{
|
||||
free_device_list(&outputDevices, &outputDeviceCount);
|
||||
free_device_list(&inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
BSDAUDIO_Deinitialize(void)
|
||||
{
|
||||
free_device_lists();
|
||||
}
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
BSDAUDIO_DetectDevices(int iscapture)
|
||||
{
|
||||
int fd;
|
||||
int available;
|
||||
|
||||
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)
|
||||
{
|
||||
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));
|
||||
audio_fd = -1;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = OBSD_OpenAudio;
|
||||
this->WaitAudio = OBSD_WaitAudio;
|
||||
this->PlayAudio = OBSD_PlayAudio;
|
||||
this->GetAudioBuf = OBSD_GetAudioBuf;
|
||||
this->CloseAudio = OBSD_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap BSD_AUDIO_bootstrap = {
|
||||
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
OBSD_WaitAudio(_THIS)
|
||||
{
|
||||
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
|
||||
/* 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);
|
||||
}
|
||||
if (iscapture) {
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
return inputDeviceCount;
|
||||
} else {
|
||||
/* Use select() for audio synchronization */
|
||||
fd_set fdset;
|
||||
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 =
|
||||
"Audio timeout - buggy audio driver? (disabled)";
|
||||
/* 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);
|
||||
this->enabled = 0;
|
||||
/* Don't try to close - may hang */
|
||||
audio_fd = -1;
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Done disabling audio\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Ready!\n");
|
||||
#endif
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
return outputDeviceCount;
|
||||
}
|
||||
#endif /* !USE_BLOCKING_WRITES */
|
||||
|
||||
return 0; /* shouldn't ever hit this. */
|
||||
}
|
||||
|
||||
static const char *
|
||||
BSDAUDIO_GetDeviceName(int index, int iscapture)
|
||||
{
|
||||
if ((iscapture) && (index < inputDeviceCount)) {
|
||||
return inputDevices[index];
|
||||
} else if ((!iscapture) && (index < outputDeviceCount)) {
|
||||
return outputDevices[index];
|
||||
}
|
||||
|
||||
SDL_SetError("No such device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
OBSD_PlayAudio(_THIS)
|
||||
BSDAUDIO_Status(_THIS)
|
||||
{
|
||||
int written, p = 0;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||
do {
|
||||
written = write(audio_fd, &mixbuf[p], mixlen - p);
|
||||
if (written > 0)
|
||||
p += written;
|
||||
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
|
||||
/* Non recoverable error has occurred. It should be reported!!! */
|
||||
perror("audio");
|
||||
break;
|
||||
}
|
||||
|
||||
if (p < written
|
||||
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
|
||||
SDL_Delay(1); /* Let a little CPU time go by */
|
||||
}
|
||||
}
|
||||
while (p < written);
|
||||
|
||||
/* If timer synchronization is enabled, set the next write frame */
|
||||
if (frame_ticks) {
|
||||
next_frame += frame_ticks;
|
||||
}
|
||||
|
||||
/* If we couldn't write, assume fatal error for now */
|
||||
if (written < 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||
#endif
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
OBSD_GetAudioBuf(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
OBSD_CloseAudio(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (audio_fd >= 0) {
|
||||
close(audio_fd);
|
||||
audio_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
void
|
||||
OBSD_Status(_THIS)
|
||||
{
|
||||
audio_info_t info;
|
||||
|
||||
if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||
fprintf(stderr, "AUDIO_GETINFO failed.\n");
|
||||
return;
|
||||
}
|
||||
@@ -269,46 +165,18 @@ OBSD_Status(_THIS)
|
||||
"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");
|
||||
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"
|
||||
@@ -324,42 +192,170 @@ OBSD_Status(_THIS)
|
||||
(info.mode == AUMODE_PLAY) ? "PLAY"
|
||||
: (info.mode = AUMODE_RECORD) ? "RECORD"
|
||||
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
|
||||
}
|
||||
#endif /* DEBUG_AUDIO */
|
||||
}
|
||||
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
BSDAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
|
||||
/* See if we need to use timed audio synchronization */
|
||||
if (this->hidden->frame_ticks) {
|
||||
/* Use timer for general audio synchronization */
|
||||
Sint32 ticks;
|
||||
|
||||
ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
|
||||
if (ticks > 0) {
|
||||
SDL_Delay(ticks);
|
||||
}
|
||||
} else {
|
||||
/* Use select() for audio synchronization */
|
||||
fd_set fdset;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(this->hidden->audio_fd, &fdset);
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Waiting for audio to get ready\n");
|
||||
#endif
|
||||
if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) {
|
||||
const char *message =
|
||||
"Audio timeout - buggy audio driver? (disabled)";
|
||||
/* In general we should never print to the screen,
|
||||
but in this case we have no other way of letting
|
||||
the user know what happened.
|
||||
*/
|
||||
fprintf(stderr, "SDL: %s\n", message);
|
||||
this->enabled = 0;
|
||||
/* Don't try to close - may hang */
|
||||
this->hidden->audio_fd = -1;
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Done disabling audio\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Ready!\n");
|
||||
#endif
|
||||
}
|
||||
#endif /* !USE_BLOCKING_WRITES */
|
||||
}
|
||||
|
||||
static void
|
||||
BSDAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
int written, p = 0;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||
do {
|
||||
written = write(this->hidden->audio_fd,
|
||||
&this->hidden->mixbuf[p],
|
||||
this->hidden->mixlen - p);
|
||||
|
||||
if (written > 0)
|
||||
p += written;
|
||||
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
|
||||
/* Non recoverable error has occurred. It should be reported!!! */
|
||||
perror("audio");
|
||||
break;
|
||||
}
|
||||
|
||||
if (p < written
|
||||
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
|
||||
SDL_Delay(1); /* Let a little CPU time go by */
|
||||
}
|
||||
}
|
||||
while (p < written);
|
||||
|
||||
/* If timer synchronization is enabled, set the next write frame */
|
||||
if (this->hidden->frame_ticks) {
|
||||
this->hidden->next_frame += this->hidden->frame_ticks;
|
||||
}
|
||||
|
||||
/* If we couldn't write, assume fatal error for now */
|
||||
if (written < 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||
#endif
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
BSDAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
BSDAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->audio_fd >= 0) {
|
||||
close(this->hidden->audio_fd);
|
||||
this->hidden->audio_fd = -1;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
char audiodev[64];
|
||||
SDL_AudioFormat format;
|
||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
SDL_AudioFormat format = 0;
|
||||
audio_info_t info;
|
||||
|
||||
/* 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 */
|
||||
this->hidden->audio_fd = open(devname, flags, 0);
|
||||
if (this->hidden->audio_fd < 0) {
|
||||
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
AUDIO_INITINFO(&info);
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
#ifdef USE_TIMER_SYNC
|
||||
frame_ticks = 0.0;
|
||||
#endif
|
||||
|
||||
/* Open the audio device */
|
||||
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
|
||||
if (audio_fd < 0) {
|
||||
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Set to play mode */
|
||||
info.mode = AUMODE_PLAY;
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
|
||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
|
||||
BSDAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Couldn't put device into play mode");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mixbuf = NULL;
|
||||
AUDIO_INITINFO(&info);
|
||||
for (format = SDL_FirstAudioFormat(spec->format);
|
||||
for (format = SDL_FirstAudioFormat(this->spec.format);
|
||||
format; format = SDL_NextAudioFormat()) {
|
||||
switch (format) {
|
||||
case AUDIO_U8:
|
||||
@@ -389,46 +385,69 @@ OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
|
||||
|
||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!format) {
|
||||
SDL_SetError("No supported encoding for 0x%x", spec->format);
|
||||
return (-1);
|
||||
BSDAUDIO_CloseDevice(this);
|
||||
SDL_SetError("No supported encoding for 0x%x", this->spec.format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spec->format = format;
|
||||
this->spec.format = format;
|
||||
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.channels = spec->channels;
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
|
||||
spec->channels = 1;
|
||||
info.play.channels = this->spec.channels;
|
||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
|
||||
this->spec.channels = 1;
|
||||
}
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.sample_rate = spec->freq;
|
||||
info.blocksize = spec->size;
|
||||
info.play.sample_rate = this->spec.freq;
|
||||
info.blocksize = this->spec.size;
|
||||
info.hiwat = 5;
|
||||
info.lowat = 3;
|
||||
(void) ioctl(audio_fd, AUDIO_SETINFO, &info);
|
||||
(void) ioctl(audio_fd, AUDIO_GETINFO, &info);
|
||||
spec->freq = info.play.sample_rate;
|
||||
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
|
||||
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
|
||||
this->spec.freq = info.play.sample_rate;
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
return (-1);
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
BSDAUDIO_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
OBSD_Status(this);
|
||||
#endif
|
||||
BSDAUDIO_Status(this);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
BSDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = BSDAUDIO_DetectDevices;
|
||||
impl->GetDeviceName = BSDAUDIO_GetDeviceName;
|
||||
impl->OpenDevice = BSDAUDIO_OpenDevice;
|
||||
impl->PlayDevice = BSDAUDIO_PlayDevice;
|
||||
impl->WaitDevice = BSDAUDIO_WaitDevice;
|
||||
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = BSDAUDIO_CloseDevice;
|
||||
impl->Deinitialize = BSDAUDIO_Deinitialize;
|
||||
|
||||
build_device_lists();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap BSD_AUDIO_bootstrap = {
|
||||
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC, BSDAUDIO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_openbsdaudio_h
|
||||
#define _SDL_openbsdaudio_h
|
||||
#ifndef _SDL_bsdaudio_h
|
||||
#define _SDL_bsdaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
@@ -47,13 +47,6 @@ struct SDL_PrivateAudioData
|
||||
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
#endif /* _SDL_bsdaudio_h */
|
||||
|
||||
#endif /* _SDL_openbsdaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -42,10 +42,10 @@ typedef struct _tMixBufferDesc
|
||||
//---------------------------------------------------------------------
|
||||
// DARTEventFunc
|
||||
//
|
||||
// This function is called by DART, when an event occures, like end of
|
||||
// This function is called by DART, when an event occurs, like end of
|
||||
// playback of a buffer, etc...
|
||||
//---------------------------------------------------------------------
|
||||
LONG APIENTRY
|
||||
static LONG APIENTRY
|
||||
DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
|
||||
{
|
||||
if (ulFlags && MIX_WRITE_COMPLETE) { // Playback of buffer completed!
|
||||
@@ -71,13 +71,12 @@ DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
static int
|
||||
DART_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
|
||||
int valid_datatype = 0;
|
||||
MCI_AMP_OPEN_PARMS AmpOpenParms;
|
||||
MCI_GENERIC_PARMS GenericParms;
|
||||
int iDeviceOrd = 0; // Default device to be used
|
||||
int bOpenShared = 1; // Try opening it shared
|
||||
int iBits = 16; // Default is 16 bits signed
|
||||
@@ -89,6 +88,15 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
int iSilence;
|
||||
int rc;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
_this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *_this->hidden));
|
||||
if (_this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
|
||||
|
||||
// First thing is to try to open a given DART device!
|
||||
SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
|
||||
// pszDeviceType should contain the device type in low word, and device ordinal in high word!
|
||||
@@ -100,30 +108,34 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
iOpenMode |= MCI_OPEN_SHAREABLE;
|
||||
|
||||
rc = mciSendCommand(0, MCI_OPEN, iOpenMode, (PVOID) & AmpOpenParms, 0);
|
||||
if (rc != MCIERR_SUCCESS) // No audio available??
|
||||
return (-1);
|
||||
if (rc != MCIERR_SUCCESS) { // No audio available??
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("DART: Couldn't open audio device.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save the device ID we got from DART!
|
||||
// We will use this in the next calls!
|
||||
iDeviceOrd = AmpOpenParms.usDeviceID;
|
||||
_this->hidden->iCurrDeviceOrd = iDeviceOrd = AmpOpenParms.usDeviceID;
|
||||
|
||||
// Determine the audio parameters from the AudioSpec
|
||||
if (spec->channels > 2)
|
||||
spec->channels = 2; // !!! FIXME: more than stereo support in OS/2?
|
||||
if (_this->spec.channels > 4)
|
||||
_this->spec.channels = 4;
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
spec->format = test_format;
|
||||
_this->spec.format = test_format;
|
||||
valid_datatype = 1;
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
// Unsigned 8 bit audio data
|
||||
iSilence = 0x80;
|
||||
iBits = 8;
|
||||
_this->hidden->iCurrBits = iBits = 8;
|
||||
break;
|
||||
|
||||
case AUDIO_S16LSB:
|
||||
// Signed 16 bit audio data
|
||||
iSilence = 0x00;
|
||||
iBits = 16;
|
||||
_this->hidden->iCurrBits = iBits = 16;
|
||||
break;
|
||||
|
||||
// !!! FIXME: int32?
|
||||
@@ -137,16 +149,16 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
if (!valid_datatype) { // shouldn't happen, but just in case...
|
||||
// Close DART, and exit with error code!
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iFreq = spec->freq;
|
||||
iChannels = spec->channels;
|
||||
_this->hidden->iCurrFreq = iFreq = _this->spec.freq;
|
||||
_this->hidden->iCurrChannels = iChannels = _this->spec.channels;
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
iBufSize = spec->size;
|
||||
SDL_CalculateAudioSpec(&_this->spec);
|
||||
_this->hidden->iCurrBufSize = iBufSize = _this->spec.size;
|
||||
|
||||
// Now query this device if it supports the given freq/bits/channels!
|
||||
SDL_memset(&(_this->hidden->MixSetupParms), 0,
|
||||
@@ -163,9 +175,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
&(_this->hidden->MixSetupParms), 0);
|
||||
if (rc != MCIERR_SUCCESS) { // The device cannot handle this format!
|
||||
// Close DART, and exit with error code!
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("Audio device doesn't support requested audio format");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
// The device can handle this format, so initialize!
|
||||
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
|
||||
@@ -173,9 +185,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
&(_this->hidden->MixSetupParms), 0);
|
||||
if (rc != MCIERR_SUCCESS) { // The device could not be opened!
|
||||
// Close DART, and exit with error code!
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("Audio device could not be set up");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
// Ok, the device is initialized.
|
||||
// Now we should allocate buffers. For this, we need a place where
|
||||
@@ -184,9 +196,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
(MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER) * iNumBufs);
|
||||
if (!(_this->hidden->pMixBuffers)) { // Not enough memory!
|
||||
// Close DART, and exit with error code!
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
SDL_SetError("Not enough memory for audio buffer descriptors");
|
||||
return (-1);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
// Now that we have the place for buffer list, we can ask DART for the
|
||||
// buffers!
|
||||
@@ -201,12 +213,12 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|| (iNumBufs != _this->hidden->BufferParms.ulNumBuffers)
|
||||
|| (_this->hidden->BufferParms.ulBufferSize == 0)) { // Could not allocate memory!
|
||||
// Close DART, and exit with error code!
|
||||
SDL_free(_this->hidden->pMixBuffers);
|
||||
_this->hidden->pMixBuffers = NULL;
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("DART could not allocate buffers");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
_this->hidden->iCurrNumBufs = iNumBufs;
|
||||
|
||||
// Ok, we have all the buffers allocated, let's mark them!
|
||||
{
|
||||
int i;
|
||||
@@ -216,24 +228,9 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
// Check if this buffer was really allocated by DART
|
||||
if ((!(_this->hidden->pMixBuffers[i].pBuffer))
|
||||
|| (!pBufferDesc)) { // Wrong buffer!
|
||||
// Close DART, and exit with error code!
|
||||
// Free buffer descriptions
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
SDL_free((void *) (_this->hidden->pMixBuffers[j].
|
||||
ulUserParm));
|
||||
}
|
||||
// and cleanup
|
||||
mciSendCommand(iDeviceOrd, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&(_this->hidden->BufferParms), 0);
|
||||
SDL_free(_this->hidden->pMixBuffers);
|
||||
_this->hidden->pMixBuffers = NULL;
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT,
|
||||
&GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("Error at internal buffer check");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
pBufferDesc->iBufferUsage = BUFFER_EMPTY;
|
||||
pBufferDesc->pSDLAudioDevice = _this;
|
||||
@@ -254,43 +251,41 @@ DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
if (DosCreateEventSem
|
||||
(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE) != NO_ERROR)
|
||||
{
|
||||
// Could not create event semaphore!
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < iNumBufs; i++)
|
||||
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
|
||||
}
|
||||
mciSendCommand(iDeviceOrd, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&(_this->hidden->BufferParms), 0);
|
||||
SDL_free(_this->hidden->pMixBuffers);
|
||||
_this->hidden->pMixBuffers = NULL;
|
||||
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
|
||||
DART_CloseDevice(_this);
|
||||
SDL_SetError("Could not create event semaphore");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
// Store the new settings in global variables
|
||||
_this->hidden->iCurrDeviceOrd = iDeviceOrd;
|
||||
_this->hidden->iCurrFreq = iFreq;
|
||||
_this->hidden->iCurrBits = iBits;
|
||||
_this->hidden->iCurrChannels = iChannels;
|
||||
_this->hidden->iCurrNumBufs = iNumBufs;
|
||||
_this->hidden->iCurrBufSize = iBufSize;
|
||||
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
DART_ThreadInit(_THIS)
|
||||
{
|
||||
return;
|
||||
/* Increase the priority of this thread to make sure that
|
||||
the audio will be continuous all the time! */
|
||||
#ifdef USE_DOSSETPRIORITY
|
||||
if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf
|
||||
("[DART_ThreadInit] : Setting priority to TimeCritical+0! (TID%d)\n",
|
||||
SDL_ThreadID());
|
||||
#endif
|
||||
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
|
||||
} else {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf
|
||||
("[DART_ThreadInit] : Setting priority to ForegroundServer+0! (TID%d)\n",
|
||||
SDL_ThreadID());
|
||||
#endif
|
||||
DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
void
|
||||
DART_WaitAudio(_THIS)
|
||||
static void
|
||||
DART_WaitDevice(_THIS)
|
||||
{
|
||||
int i;
|
||||
pMixBufferDesc pBufDesc;
|
||||
@@ -308,8 +303,8 @@ DART_WaitAudio(_THIS)
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
DART_PlayAudio(_THIS)
|
||||
static void
|
||||
DART_PlayDevice(_THIS)
|
||||
{
|
||||
int iFreeBuf = _this->hidden->iNextFreeBuffer;
|
||||
pMixBufferDesc pBufDesc;
|
||||
@@ -328,8 +323,8 @@ DART_PlayAudio(_THIS)
|
||||
_this->hidden->iNextFreeBuffer = iFreeBuf;
|
||||
}
|
||||
|
||||
Uint8 *
|
||||
DART_GetAudioBuf(_THIS)
|
||||
static Uint8 *
|
||||
DART_GetDeviceBuf(_THIS)
|
||||
{
|
||||
int iFreeBuf;
|
||||
Uint8 *pResult;
|
||||
@@ -348,125 +343,110 @@ DART_GetAudioBuf(_THIS)
|
||||
return pResult;
|
||||
}
|
||||
} else
|
||||
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n",
|
||||
printf("[DART_GetDeviceBuf] : ERROR! pBufDesc = %p\n",
|
||||
pBufDesc);
|
||||
} else
|
||||
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n",
|
||||
printf("[DART_GetDeviceBuf] : ERROR! _this->hidden = %p\n",
|
||||
_this->hidden);
|
||||
} else
|
||||
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
|
||||
printf("[DART_GetDeviceBuf] : ERROR! _this = %p\n", _this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
DART_WaitDone(_THIS)
|
||||
{
|
||||
pMixBufferDesc pBufDesc;
|
||||
ULONG ulPostCount;
|
||||
APIRET rc;
|
||||
ULONG ulPostCount = 0;
|
||||
APIRET rc = NO_ERROR;
|
||||
|
||||
pBufDesc = (pMixBufferDesc)
|
||||
_this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
|
||||
|
||||
pBufDesc =
|
||||
(pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->
|
||||
iLastPlayedBuf].
|
||||
ulUserParm;
|
||||
rc = NO_ERROR;
|
||||
while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc == NO_ERROR)) {
|
||||
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
|
||||
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DART_CloseAudio(_THIS)
|
||||
static void
|
||||
DART_CloseDevice(_THIS)
|
||||
{
|
||||
MCI_GENERIC_PARMS GenericParms;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
// Stop DART playback
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT,
|
||||
&GenericParms, 0);
|
||||
if (rc != MCIERR_SUCCESS) {
|
||||
if (_this->hidden != NULL) {
|
||||
// Stop DART playback
|
||||
if (_this->hidden->iCurrDeviceOrd) {
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP,
|
||||
MCI_WAIT, &GenericParms, 0);
|
||||
#ifdef SFX_DEBUG_BUILD
|
||||
printf("Could not stop DART playback!\n");
|
||||
fflush(stdout);
|
||||
if (rc != MCIERR_SUCCESS) {
|
||||
printf("Could not stop DART playback!\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Close event semaphore
|
||||
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
|
||||
}
|
||||
|
||||
// Free memory of buffer descriptions
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < _this->hidden->iCurrNumBufs; i++)
|
||||
// Close event semaphore
|
||||
if (_this->hidden->hevAudioBufferPlayed) {
|
||||
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
|
||||
_this->hidden->hevAudioBufferPlayed = 0;
|
||||
}
|
||||
|
||||
// Free memory of buffer descriptions
|
||||
for (i = 0; i < _this->hidden->iCurrNumBufs; i++) {
|
||||
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
|
||||
_this->hidden->pMixBuffers[i].ulUserParm = 0;
|
||||
}
|
||||
_this->hidden->iCurrNumBufs = 0;
|
||||
|
||||
// Deallocate buffers
|
||||
if (_this->hidden->iCurrDeviceOrd) {
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&(_this->hidden->BufferParms), 0);
|
||||
}
|
||||
|
||||
// Free bufferlist
|
||||
if (_this->hidden->pMixBuffers != NULL) {
|
||||
SDL_free(_this->hidden->pMixBuffers);
|
||||
_this->hidden->pMixBuffers = NULL;
|
||||
}
|
||||
|
||||
// Close dart
|
||||
if (_this->hidden->iCurrDeviceOrd) {
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE,
|
||||
MCI_WAIT, &(GenericParms), 0);
|
||||
}
|
||||
_this->hidden->iCurrDeviceOrd = 0;
|
||||
|
||||
SDL_free(_this->hidden);
|
||||
_this->hidden = NULL;
|
||||
}
|
||||
|
||||
// Deallocate buffers
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&(_this->hidden->BufferParms), 0);
|
||||
|
||||
// Free bufferlist
|
||||
SDL_free(_this->hidden->pMixBuffers);
|
||||
_this->hidden->pMixBuffers = NULL;
|
||||
|
||||
// Close dart
|
||||
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT,
|
||||
&(GenericParms), 0);
|
||||
}
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
int
|
||||
Audio_Available(void)
|
||||
static int
|
||||
DART_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
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 = DART_OpenAudio;
|
||||
this->ThreadInit = DART_ThreadInit;
|
||||
this->WaitAudio = DART_WaitAudio;
|
||||
this->PlayAudio = DART_PlayAudio;
|
||||
this->GetAudioBuf = DART_GetAudioBuf;
|
||||
this->WaitDone = DART_WaitDone;
|
||||
this->CloseAudio = DART_CloseAudio;
|
||||
impl->OpenDevice = DART_OpenDevice;
|
||||
impl->ThreadInit = DART_ThreadInit;
|
||||
impl->WaitDevice = DART_WaitDevice;
|
||||
impl->GetDeviceBuf = DART_GetDeviceBuf;
|
||||
impl->PlayDevice = DART_PlayDevice;
|
||||
impl->WaitDone = DART_WaitDone;
|
||||
impl->CloseDevice = DART_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this right? */
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap DART_bootstrap = {
|
||||
"dart", "OS/2 Direct Audio RouTines (DART)",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
"dart", "OS/2 Direct Audio RouTines (DART)", DART_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,14 +21,15 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_dart_h
|
||||
#define _SDL_dart_h
|
||||
|
||||
#define INCL_TYPES
|
||||
#define INCL_DOSSEMAPHORES
|
||||
#define INCL_DOSRESOURCES
|
||||
#define INCL_DOSMISC
|
||||
#define INCL_DOSERRORS
|
||||
#define INCL_DOSPROCESS
|
||||
|
||||
#define INCL_OS2MM
|
||||
#define INCL_MMIOOS2
|
||||
@@ -60,5 +61,6 @@ struct SDL_PrivateAudioData
|
||||
HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART
|
||||
};
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
#endif /* _SDL_dart_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -28,85 +28,11 @@
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_dcaudio.h"
|
||||
|
||||
#include "aica.h"
|
||||
#include <dc/spu.h>
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DCAUD_WaitAudio(_THIS);
|
||||
static void DCAUD_PlayAudio(_THIS);
|
||||
static Uint8 *DCAUD_GetAudioBuf(_THIS);
|
||||
static void DCAUD_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
static int
|
||||
DCAUD_Available(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
DCAUD_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
DCAUD_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = DCAUD_OpenAudio;
|
||||
this->WaitAudio = DCAUD_WaitAudio;
|
||||
this->PlayAudio = DCAUD_PlayAudio;
|
||||
this->GetAudioBuf = DCAUD_GetAudioBuf;
|
||||
this->CloseAudio = DCAUD_CloseAudio;
|
||||
|
||||
this->free = DCAUD_DeleteDevice;
|
||||
|
||||
spu_init();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap DCAUD_bootstrap = {
|
||||
"dcaudio", "Dreamcast AICA audio",
|
||||
DCAUD_Available, DCAUD_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DCAUD_WaitAudio(_THIS)
|
||||
{
|
||||
if (this->hidden->playing) {
|
||||
/* wait */
|
||||
while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
|
||||
thd_pass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SPU_RAM_BASE 0xa0800000
|
||||
|
||||
static void
|
||||
@@ -152,7 +78,7 @@ spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size)
|
||||
}
|
||||
|
||||
static void
|
||||
DCAUD_PlayAudio(_THIS)
|
||||
DCAUD_PlayDevice(_THIS)
|
||||
{
|
||||
SDL_AudioSpec *spec = &this->spec;
|
||||
unsigned int offset;
|
||||
@@ -200,28 +126,59 @@ DCAUD_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DCAUD_GetAudioBuf(_THIS)
|
||||
DCAUD_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DCAUD_CloseAudio(_THIS)
|
||||
DCAUD_WaitDevice(_THIS)
|
||||
{
|
||||
aica_stop(0);
|
||||
if (this->spec.channels == 2)
|
||||
aica_stop(1);
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
if (this->hidden->playing) {
|
||||
/* wait */
|
||||
while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
|
||||
thd_pass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DCAUD_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden != NULL) {
|
||||
aica_stop(0);
|
||||
if (this->spec.channels == 2) {
|
||||
aica_stop(1);
|
||||
}
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
|
||||
/* !!! FIXME: is there a reverse of spu_init()? */
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
DCAUD_OpenDevice(_THIS, SDL_AudioSpec * spec)
|
||||
{
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
int valid_datatype = 0;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
spu_init();
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
spec->format = test_format;
|
||||
switch (test_format) {
|
||||
@@ -238,8 +195,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||
DCAUD_CloseDevice(this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (spec->channels > 2)
|
||||
@@ -252,7 +210,9 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
this->hidden->mixlen = spec->size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
return (-1);
|
||||
DCAUD_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
|
||||
this->hidden->leftpos = 0x11000;
|
||||
@@ -261,7 +221,25 @@ DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
this->hidden->nextbuf = 0;
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
DCAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = DCAUD_OpenDevice;
|
||||
impl->PlayDevice = DCAUD_PlayDevice;
|
||||
impl->WaitDevice = DCAUD_WaitDevice;
|
||||
impl->GetDeviceBuf = DCAUD_GetDeviceBuf;
|
||||
impl->CloseDevice = DCAUD_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap DCAUD_bootstrap = {
|
||||
"dcaudio", "Dreamcast AICA audio", DCAUD_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_diskaudio.h"
|
||||
|
||||
/* The tag name used by DISK audio */
|
||||
@@ -46,90 +45,27 @@
|
||||
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
|
||||
#define DISKDEFAULT_WRITEDELAY 150
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DISKAUD_WaitAudio(_THIS);
|
||||
static void DISKAUD_PlayAudio(_THIS);
|
||||
static Uint8 *DISKAUD_GetAudioBuf(_THIS);
|
||||
static void DISKAUD_CloseAudio(_THIS);
|
||||
|
||||
static const char *
|
||||
DISKAUD_GetOutputFilename(void)
|
||||
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;
|
||||
const char *envr;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
if (devname == NULL) {
|
||||
devname = SDL_getenv(DISKENVR_OUTFILE);
|
||||
if (devname == NULL) {
|
||||
devname = DISKDEFAULT_OUTFILE;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
envr = SDL_getenv(DISKENVR_WRITEDELAY);
|
||||
this->hidden->write_delay =
|
||||
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = DISKAUD_OpenAudio;
|
||||
this->WaitAudio = DISKAUD_WaitAudio;
|
||||
this->PlayAudio = DISKAUD_PlayAudio;
|
||||
this->GetAudioBuf = DISKAUD_GetAudioBuf;
|
||||
this->CloseAudio = DISKAUD_CloseAudio;
|
||||
|
||||
this->free = DISKAUD_DeleteDevice;
|
||||
|
||||
return this;
|
||||
return devname;
|
||||
}
|
||||
|
||||
AudioBootStrap DISKAUD_bootstrap = {
|
||||
DISKAUD_DRIVER_NAME, "direct-to-disk audio",
|
||||
DISKAUD_Available, DISKAUD_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DISKAUD_WaitAudio(_THIS)
|
||||
DISKAUD_WaitDevice(_THIS)
|
||||
{
|
||||
SDL_Delay(this->hidden->write_delay);
|
||||
}
|
||||
|
||||
static void
|
||||
DISKAUD_PlayAudio(_THIS)
|
||||
DISKAUD_PlayDevice(_THIS)
|
||||
{
|
||||
int written;
|
||||
|
||||
@@ -147,49 +83,86 @@ DISKAUD_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DISKAUD_GetAudioBuf(_THIS)
|
||||
DISKAUD_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
DISKAUD_CloseAudio(_THIS)
|
||||
DISKAUD_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->output != NULL) {
|
||||
SDL_RWclose(this->hidden->output);
|
||||
this->hidden->output = NULL;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->output != NULL) {
|
||||
SDL_RWclose(this->hidden->output);
|
||||
this->hidden->output = NULL;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
const char *fname = DISKAUD_GetOutputFilename();
|
||||
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
|
||||
const char *fname = DISKAUD_GetOutputFilename(devname);
|
||||
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc(sizeof (*this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, sizeof (*this->hidden));
|
||||
|
||||
/* Open the audio device */
|
||||
this->hidden->output = SDL_RWFromFile(fname, "wb");
|
||||
if (this->hidden->output == NULL) {
|
||||
return (-1);
|
||||
DISKAUD_CloseDevice(this);
|
||||
return 0;
|
||||
}
|
||||
#if HAVE_STDIO_H
|
||||
fprintf(stderr, "WARNING: You are using the SDL disk writer"
|
||||
" audio driver!\n Writing to file [%s].\n", fname);
|
||||
#endif
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
this->hidden->mixlen = spec->size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
return (-1);
|
||||
DISKAUD_CloseDevice(this);
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->write_delay =
|
||||
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
|
||||
|
||||
#if HAVE_STDIO_H
|
||||
fprintf(stderr,
|
||||
"WARNING: You are using the SDL disk writer audio driver!\n"
|
||||
" Writing to file [%s].\n", fname);
|
||||
#endif
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
DISKAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = DISKAUD_OpenDevice;
|
||||
impl->WaitDevice = DISKAUD_WaitDevice;
|
||||
impl->PlayDevice = DISKAUD_PlayDevice;
|
||||
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
|
||||
impl->CloseDevice = DISKAUD_CloseDevice;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap DISKAUD_bootstrap = {
|
||||
DISKAUD_DRIVER_NAME, "direct-to-disk audio", DISKAUD_Init, 1
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "SDL_rwops.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
/* !!! FIXME: merge this driver with "dsp". */
|
||||
|
||||
/* Allow access to a raw mixing buffer */
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -57,89 +59,353 @@
|
||||
#define DMA_DRIVER_NAME "dma"
|
||||
|
||||
/* 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
|
||||
Audio_Available(void)
|
||||
test_for_mmap(int fd)
|
||||
{
|
||||
int available;
|
||||
int fd;
|
||||
|
||||
available = 0;
|
||||
|
||||
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
|
||||
if (fd >= 0) {
|
||||
int caps;
|
||||
struct audio_buf_info info;
|
||||
|
||||
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
|
||||
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
|
||||
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) {
|
||||
available = 1;
|
||||
int caps = 0;
|
||||
struct audio_buf_info info;
|
||||
if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
|
||||
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
|
||||
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0))
|
||||
{
|
||||
size_t len = info.fragstotal * info.fragsize;
|
||||
Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
munmap(buf, len);
|
||||
return 1;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return (available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
free_device_list(char ***devs, int *count)
|
||||
{
|
||||
SDL_FreeUnixAudioDevices(devs, count);
|
||||
}
|
||||
|
||||
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, test_for_mmap, devs, count);
|
||||
}
|
||||
|
||||
static inline void
|
||||
build_device_lists(void)
|
||||
{
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
free_device_lists(void)
|
||||
{
|
||||
free_device_list(&outputDevices, &outputDeviceCount);
|
||||
free_device_list(&inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static void DMA_Deinitialize(void)
|
||||
{
|
||||
free_device_lists();
|
||||
}
|
||||
|
||||
static int
|
||||
DMA_DetectDevices(int iscapture)
|
||||
{
|
||||
if (iscapture) {
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
return inputDeviceCount;
|
||||
} else {
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
return outputDeviceCount;
|
||||
}
|
||||
|
||||
return 0; /* shouldn't ever hit this. */
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
DMA_GetDeviceName(int index, int iscapture)
|
||||
{
|
||||
if ((iscapture) && (index < inputDeviceCount)) {
|
||||
return inputDevices[index];
|
||||
} else if ((!iscapture) && (index < outputDeviceCount)) {
|
||||
return outputDevices[index];
|
||||
}
|
||||
|
||||
SDL_SetError("No such device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo)
|
||||
{
|
||||
int frag_spec;
|
||||
int value;
|
||||
|
||||
/* Close and then reopen the audio device */
|
||||
close(audio_fd);
|
||||
audio_fd = open(audiodev, O_RDWR, 0);
|
||||
if (audio_fd < 0) {
|
||||
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Determine the power of two of the fragment size */
|
||||
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
|
||||
if ((0x01 << frag_spec) != this->spec.size) {
|
||||
SDL_SetError("Fragment size must be a power of two");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the audio buffering parameters */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
||||
SDL_SetError("Couldn't set audio fragment spec");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the audio format */
|
||||
value = format;
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
|
||||
SDL_SetError("Couldn't set audio format");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set mono or stereo audio */
|
||||
value = (this->spec.channels > 1);
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
|
||||
(value != stereo)) {
|
||||
SDL_SetError("Couldn't set audio channels");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the DSP frequency */
|
||||
value = this->spec.freq;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||
SDL_SetError("Couldn't set audio frequency");
|
||||
return (-1);
|
||||
}
|
||||
this->spec.freq = value;
|
||||
|
||||
/* We successfully re-opened the audio */
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
DMA_CloseDevice(_THIS)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
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 SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
|
||||
static int
|
||||
DMA_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
int format;
|
||||
int stereo;
|
||||
int value;
|
||||
SDL_AudioFormat test_format;
|
||||
struct audio_buf_info info;
|
||||
|
||||
/* 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 = (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)) {
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
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;
|
||||
/* Open the audio device */
|
||||
audio_fd = open(devname, flags, 0);
|
||||
if (audio_fd < 0) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
dma_buf = NULL;
|
||||
ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
/* Get a list of supported hardware formats */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't get audio format list");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this;
|
||||
/* Try for a closest match on audio format */
|
||||
format = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!format && test_format;) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
#endif
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
if (value & AFMT_U8) {
|
||||
format = AFMT_U8;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S8:
|
||||
if (value & AFMT_S8) {
|
||||
format = AFMT_S8;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S16LSB:
|
||||
if (value & AFMT_S16_LE) {
|
||||
format = AFMT_S16_LE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S16MSB:
|
||||
if (value & AFMT_S16_BE) {
|
||||
format = AFMT_S16_BE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_U16LSB:
|
||||
if (value & AFMT_U16_LE) {
|
||||
format = AFMT_U16_LE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_U16MSB:
|
||||
if (value & AFMT_U16_BE) {
|
||||
format = AFMT_U16_BE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
format = 0;
|
||||
break;
|
||||
}
|
||||
if (!format) {
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
}
|
||||
if (format == 0) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return 0;
|
||||
}
|
||||
this->spec.format = test_format;
|
||||
|
||||
/* Set the audio format */
|
||||
value = format;
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set audio format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set mono or stereo audio (currently only two channels supported) */
|
||||
stereo = (this->spec.channels > 1);
|
||||
ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
|
||||
if (stereo) {
|
||||
this->spec.channels = 2;
|
||||
} else {
|
||||
this->spec.channels = 1;
|
||||
}
|
||||
|
||||
/* Because some drivers don't allow setting the buffer size
|
||||
after setting the format, we must re-open the audio device
|
||||
once we know what format and channels are supported
|
||||
*/
|
||||
if (DMA_ReopenAudio(this, devname, format, stereo) < 0) {
|
||||
DMA_CloseDevice(this);
|
||||
/* Error is set by DMA_ReopenAudio() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory map the audio buffer */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't get OSPACE parameters");
|
||||
return 0;
|
||||
}
|
||||
this->spec.size = info.fragsize;
|
||||
this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8);
|
||||
this->spec.samples /= this->spec.channels;
|
||||
num_buffers = info.fragstotal;
|
||||
dma_len = num_buffers * this->spec.size;
|
||||
dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
|
||||
audio_fd, 0);
|
||||
if (dma_buf == MAP_FAILED) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("DMA memory map failed");
|
||||
dma_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(dma_buf, this->spec.silence, dma_len);
|
||||
|
||||
/* Check to see if we need to use select() workaround */
|
||||
{
|
||||
char *workaround;
|
||||
workaround = SDL_getenv("SDL_DSP_NOSELECT");
|
||||
if (workaround) {
|
||||
frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
|
||||
next_frame = SDL_GetTicks() + frame_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
/* Trigger audio playback */
|
||||
value = 0;
|
||||
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
|
||||
value = PCM_ENABLE_OUTPUT;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) {
|
||||
DMA_CloseDevice(this);
|
||||
SDL_SetError("Couldn't trigger audio output");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap DMA_bootstrap = {
|
||||
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DMA_WaitAudio(_THIS)
|
||||
DMA_WaitDevice(_THIS)
|
||||
{
|
||||
fd_set fdset;
|
||||
|
||||
@@ -189,8 +455,8 @@ DMA_WaitAudio(_THIS)
|
||||
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;
|
||||
frame_ticks = (float) (this->spec.samples * 1000) /
|
||||
this->spec.freq;
|
||||
next_frame = SDL_GetTicks() + frame_ticks;
|
||||
#else
|
||||
this->enabled = 0;
|
||||
@@ -208,7 +474,7 @@ DMA_WaitAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
DMA_PlayAudio(_THIS)
|
||||
DMA_PlayDevice(_THIS)
|
||||
{
|
||||
/* If timer synchronization is enabled, set the next write frame */
|
||||
if (frame_ticks) {
|
||||
@@ -218,7 +484,7 @@ DMA_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DMA_GetAudioBuf(_THIS)
|
||||
DMA_GetDeviceBuf(_THIS)
|
||||
{
|
||||
count_info info;
|
||||
int playing;
|
||||
@@ -243,225 +509,26 @@ DMA_GetAudioBuf(_THIS)
|
||||
return (dma_buf + (filling * this->spec.size));
|
||||
}
|
||||
|
||||
static void
|
||||
DMA_CloseAudio(_THIS)
|
||||
{
|
||||
if (dma_buf != NULL) {
|
||||
munmap(dma_buf, dma_len);
|
||||
dma_buf = NULL;
|
||||
}
|
||||
if (audio_fd >= 0) {
|
||||
close(audio_fd);
|
||||
audio_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
|
||||
SDL_AudioSpec * spec)
|
||||
DMA_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
int frag_spec;
|
||||
int value;
|
||||
/* 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;
|
||||
|
||||
/* Close and then reopen the audio device */
|
||||
close(audio_fd);
|
||||
audio_fd = open(audiodev, O_RDWR, 0);
|
||||
if (audio_fd < 0) {
|
||||
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
/* Determine the power of two of the fragment size */
|
||||
for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec);
|
||||
if ((0x01 << frag_spec) != spec->size) {
|
||||
SDL_SetError("Fragment size must be a power of two");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the audio buffering parameters */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
||||
SDL_SetError("Couldn't set audio fragment spec");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the audio format */
|
||||
value = format;
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
|
||||
SDL_SetError("Couldn't set audio format");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set mono or stereo audio */
|
||||
value = (spec->channels > 1);
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
|
||||
(value != stereo)) {
|
||||
SDL_SetError("Couldn't set audio channels");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set the DSP frequency */
|
||||
value = spec->freq;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||
SDL_SetError("Couldn't set audio frequency");
|
||||
return (-1);
|
||||
}
|
||||
spec->freq = value;
|
||||
|
||||
/* We successfully re-opened the audio */
|
||||
return (0);
|
||||
build_device_lists();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
DMA_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
{
|
||||
char audiodev[1024];
|
||||
int format;
|
||||
int stereo;
|
||||
int value;
|
||||
SDL_AudioFormat test_format;
|
||||
struct audio_buf_info info;
|
||||
|
||||
/* Reset the timer synchronization flag */
|
||||
frame_ticks = 0.0;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
dma_buf = NULL;
|
||||
ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
|
||||
|
||||
/* Get a list of supported hardware formats */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||
SDL_SetError("Couldn't get audio format list");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
format = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
!format && test_format;) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
#endif
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
if (value & AFMT_U8) {
|
||||
format = AFMT_U8;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S8:
|
||||
if (value & AFMT_S8) {
|
||||
format = AFMT_S8;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S16LSB:
|
||||
if (value & AFMT_S16_LE) {
|
||||
format = AFMT_S16_LE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_S16MSB:
|
||||
if (value & AFMT_S16_BE) {
|
||||
format = AFMT_S16_BE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_U16LSB:
|
||||
if (value & AFMT_U16_LE) {
|
||||
format = AFMT_U16_LE;
|
||||
}
|
||||
break;
|
||||
case AUDIO_U16MSB:
|
||||
if (value & AFMT_U16_BE) {
|
||||
format = AFMT_U16_BE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
format = 0;
|
||||
break;
|
||||
}
|
||||
if (!format) {
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
}
|
||||
if (format == 0) {
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return (-1);
|
||||
}
|
||||
spec->format = test_format;
|
||||
|
||||
/* Set the audio format */
|
||||
value = format;
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
|
||||
SDL_SetError("Couldn't set audio format");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Set mono or stereo audio (currently only two channels supported) */
|
||||
stereo = (spec->channels > 1);
|
||||
ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
|
||||
if (stereo) {
|
||||
spec->channels = 2;
|
||||
} else {
|
||||
spec->channels = 1;
|
||||
}
|
||||
|
||||
/* Because some drivers don't allow setting the buffer size
|
||||
after setting the format, we must re-open the audio device
|
||||
once we know what format and channels are supported
|
||||
*/
|
||||
if (DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0) {
|
||||
/* Error is set by DMA_ReopenAudio() */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Memory map the audio buffer */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
||||
SDL_SetError("Couldn't get OSPACE parameters");
|
||||
return (-1);
|
||||
}
|
||||
spec->size = info.fragsize;
|
||||
spec->samples = spec->size / ((spec->format & 0xFF) / 8);
|
||||
spec->samples /= spec->channels;
|
||||
num_buffers = info.fragstotal;
|
||||
dma_len = num_buffers * spec->size;
|
||||
dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
|
||||
audio_fd, 0);
|
||||
if (dma_buf == MAP_FAILED) {
|
||||
SDL_SetError("DMA memory map failed");
|
||||
dma_buf = NULL;
|
||||
return (-1);
|
||||
}
|
||||
SDL_memset(dma_buf, spec->silence, dma_len);
|
||||
|
||||
/* Check to see if we need to use select() workaround */
|
||||
{
|
||||
char *workaround;
|
||||
workaround = SDL_getenv("SDL_DSP_NOSELECT");
|
||||
if (workaround) {
|
||||
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
|
||||
next_frame = SDL_GetTicks() + frame_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
/* Trigger audio playback */
|
||||
value = 0;
|
||||
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
|
||||
value = PCM_ENABLE_OUTPUT;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) {
|
||||
SDL_SetError("Couldn't trigger audio output");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
}
|
||||
AudioBootStrap DMA_bootstrap = {
|
||||
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", DMA_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_dspaudio_h
|
||||
#define _SDL_dspaudio_h
|
||||
#ifndef _SDL_dmaaudio_h
|
||||
#define _SDL_dmaaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -49,6 +49,7 @@ struct SDL_PrivateAudioData
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
/* !!! FIXME: remove these. */
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define dma_buf (this->hidden->dma_buf)
|
||||
@@ -57,5 +58,6 @@ struct SDL_PrivateAudioData
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
|
||||
#endif /* _SDL_dspaudio_h */
|
||||
#endif /* _SDL_dmaaudio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -45,73 +45,12 @@
|
||||
#define alSetWidth(x,y) ALsetwidth(x,y)
|
||||
#endif
|
||||
|
||||
/* Audio driver functions */
|
||||
static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void AL_WaitAudio(_THIS);
|
||||
static void AL_PlayAudio(_THIS);
|
||||
static Uint8 *AL_GetAudioBuf(_THIS);
|
||||
static void AL_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = AL_OpenAudio;
|
||||
this->WaitAudio = AL_WaitAudio;
|
||||
this->PlayAudio = AL_PlayAudio;
|
||||
this->GetAudioBuf = AL_GetAudioBuf;
|
||||
this->CloseAudio = AL_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap DMEDIA_bootstrap = {
|
||||
"AL", "IRIX DMedia audio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
|
||||
void static
|
||||
AL_WaitAudio(_THIS)
|
||||
IRIXAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
Sint32 timeleft;
|
||||
|
||||
timeleft = this->spec.samples - alGetFillable(audio_port);
|
||||
timeleft = this->spec.samples - alGetFillable(this->hidden->audio_port);
|
||||
if (timeleft > 0) {
|
||||
timeleft /= (this->spec.freq / 1000);
|
||||
SDL_Delay((Uint32) timeleft);
|
||||
@@ -119,61 +58,78 @@ AL_WaitAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
AL_PlayAudio(_THIS)
|
||||
IRIXAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
/* Write the audio data out */
|
||||
if (alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0) {
|
||||
ALport port = this->hidden->audio_port;
|
||||
Uint8 *mixbuf = this->hidden->mixbuf;
|
||||
if (alWriteFrames(port, mixbuf, this->spec.samples) < 0) {
|
||||
/* Assume fatal error, for now */
|
||||
this->enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
AL_GetAudioBuf(_THIS)
|
||||
IRIXAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
AL_CloseAudio(_THIS)
|
||||
IRIXAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (audio_port != NULL) {
|
||||
alClosePort(audio_port);
|
||||
audio_port = NULL;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->audio_port != NULL) {
|
||||
alClosePort(this->hidden->audio_port);
|
||||
this->hidden->audio_port = NULL;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
IRIXAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
long width = 0;
|
||||
long fmt = 0;
|
||||
int valid = 0;
|
||||
|
||||
/* !!! FIXME: Handle multiple devices and capture? */
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
#ifdef OLD_IRIX_AUDIO
|
||||
{
|
||||
long audio_param[2];
|
||||
audio_param[0] = AL_OUTPUT_RATE;
|
||||
audio_param[1] = spec->freq;
|
||||
audio_param[1] = this->spec.freq;
|
||||
valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
|
||||
}
|
||||
#else
|
||||
{
|
||||
ALpv audio_param;
|
||||
audio_param.param = AL_RATE;
|
||||
audio_param.value.i = spec->freq;
|
||||
audio_param.value.i = this->spec.freq;
|
||||
valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
while ((!valid) && (test_format)) {
|
||||
valid = 1;
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
switch (test_format) {
|
||||
case AUDIO_S8:
|
||||
@@ -203,30 +159,31 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
ALconfig audio_config = alNewConfig();
|
||||
valid = 0;
|
||||
if (audio_config) {
|
||||
if (alSetChannels(audio_config, spec->channels) < 0) {
|
||||
if (spec->channels > 2) { /* can't handle > stereo? */
|
||||
spec->channels = 2; /* try again below. */
|
||||
if (alSetChannels(audio_config, this->spec.channels) < 0) {
|
||||
if (this->spec.channels > 2) { /* can't handle > stereo? */
|
||||
this->spec.channels = 2; /* try again below. */
|
||||
}
|
||||
}
|
||||
|
||||
if ((alSetSampFmt(audio_config, fmt) >= 0) &&
|
||||
((!width) || (alSetWidth(audio_config, width) >= 0)) &&
|
||||
(alSetQueueSize(audio_config, spec->samples * 2) >= 0) &&
|
||||
(alSetChannels(audio_config, spec->channels) >= 0)) {
|
||||
(alSetQueueSize(audio_config,this->spec.samples*2) >= 0) &&
|
||||
(alSetChannels(audio_config, this->spec.channels) >= 0)) {
|
||||
|
||||
audio_port = alOpenPort("SDL audio", "w", audio_config);
|
||||
if (audio_port == NULL) {
|
||||
this->hidden->audio_port = alOpenPort("SDL audio", "w",
|
||||
audio_config);
|
||||
if (this->hidden->audio_port == NULL) {
|
||||
/* docs say AL_BAD_CHANNELS happens here, too. */
|
||||
int err = oserror();
|
||||
if (err == AL_BAD_CHANNELS) {
|
||||
spec->channels = 2;
|
||||
alSetChannels(audio_config, spec->channels);
|
||||
audio_port = alOpenPort("SDL audio", "w",
|
||||
audio_config);
|
||||
this->spec.channels = 2;
|
||||
alSetChannels(audio_config, this->spec.channels);
|
||||
this->hidden->audio_port = alOpenPort("SDL audio", "w",
|
||||
audio_config);
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_port != NULL) {
|
||||
if (this->hidden->audio_port != NULL) {
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
@@ -237,23 +194,43 @@ AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
IRIXAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size);
|
||||
if (mixbuf == NULL) {
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
IRIXAUDIO_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
IRIXAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = DSP_OpenDevice;
|
||||
impl->PlayDevice = DSP_PlayDevice;
|
||||
impl->WaitDevice = DSP_WaitDevice;
|
||||
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
||||
impl->CloseDevice = DSP_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: not true, I think. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap IRIXAUDIO_bootstrap = {
|
||||
"AL", "IRIX DMedia audio", IRIXAUDIO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_irixaudio_h
|
||||
#define _SDL_irixaudio_h
|
||||
|
||||
#include <dmedia/audio.h>
|
||||
|
||||
@@ -33,15 +33,10 @@
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* The handle for the audio device */
|
||||
ALport audio_port;
|
||||
|
||||
Uint8 *mixbuf; /* The app mixing buffer */
|
||||
ALport audio_port; /* The handle for the audio device */
|
||||
Uint8 *mixbuf; /* The app mixing buffer */
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_port (this->hidden->audio_port)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#endif /* _SDL_irixaudio_h */
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -55,156 +55,158 @@
|
||||
#define DSP_DRIVER_NAME "dsp"
|
||||
|
||||
/* Open the audio device for playback, and don't block if busy */
|
||||
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
|
||||
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
|
||||
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DSP_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DSP_WaitAudio(_THIS);
|
||||
static void DSP_PlayAudio(_THIS);
|
||||
static Uint8 *DSP_GetAudioBuf(_THIS);
|
||||
static void DSP_CloseAudio(_THIS);
|
||||
static char **outputDevices = NULL;
|
||||
static int outputDeviceCount = 0;
|
||||
static char **inputDevices = NULL;
|
||||
static int inputDeviceCount = 0;
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
static inline void
|
||||
free_device_list(char ***devs, int *count)
|
||||
{
|
||||
int fd;
|
||||
int available;
|
||||
|
||||
available = 0;
|
||||
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
|
||||
if (fd >= 0) {
|
||||
available = 1;
|
||||
close(fd);
|
||||
}
|
||||
return (available);
|
||||
SDL_FreeUnixAudioDevices(devs, count);
|
||||
}
|
||||
|
||||
static 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 inline void
|
||||
build_device_lists(void)
|
||||
{
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
free_device_lists(void)
|
||||
{
|
||||
free_device_list(&outputDevices, &outputDeviceCount);
|
||||
free_device_list(&inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
DSP_Deinitialize(void)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
free_device_lists();
|
||||
}
|
||||
|
||||
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));
|
||||
static int
|
||||
DSP_DetectDevices(int iscapture)
|
||||
{
|
||||
if (iscapture) {
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
return inputDeviceCount;
|
||||
} else {
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
return outputDeviceCount;
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
|
||||
return 0; /* shouldn't ever hit this. */
|
||||
}
|
||||
|
||||
static const char *
|
||||
DSP_GetDeviceName(int index, int iscapture)
|
||||
{
|
||||
if ((iscapture) && (index < inputDeviceCount)) {
|
||||
return inputDevices[index];
|
||||
} else if ((!iscapture) && (index < outputDeviceCount)) {
|
||||
return outputDevices[index];
|
||||
}
|
||||
|
||||
SDL_SetError("No such device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DSP_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
AudioBootStrap DSP_bootstrap = {
|
||||
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DSP_WaitAudio(_THIS)
|
||||
{
|
||||
/* Not needed at all since OSS handles waiting automagically */
|
||||
}
|
||||
|
||||
static void
|
||||
DSP_PlayAudio(_THIS)
|
||||
{
|
||||
if (write(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_GetAudioBuf(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
DSP_CloseAudio(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (audio_fd >= 0) {
|
||||
close(audio_fd);
|
||||
audio_fd = -1;
|
||||
if (this->hidden->audio_fd >= 0) {
|
||||
close(this->hidden->audio_fd);
|
||||
this->hidden->audio_fd = -1;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
DSP_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
char audiodev[1024];
|
||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
int format;
|
||||
int value;
|
||||
int frag_spec;
|
||||
SDL_AudioFormat test_format;
|
||||
|
||||
/* 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);
|
||||
/* 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]);
|
||||
}
|
||||
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));
|
||||
|
||||
/* Open the audio device */
|
||||
this->hidden->audio_fd = open(devname, flags, 0);
|
||||
if (this->hidden->audio_fd < 0) {
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
this->hidden->mixbuf = NULL;
|
||||
|
||||
/* Make the file descriptor use blocking writes with fcntl() */
|
||||
{
|
||||
long flags;
|
||||
flags = fcntl(audio_fd, F_GETFL);
|
||||
flags &= ~O_NONBLOCK;
|
||||
if (fcntl(audio_fd, F_SETFL, flags) < 0) {
|
||||
long ctlflags;
|
||||
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
|
||||
ctlflags &= ~O_NONBLOCK;
|
||||
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set audio blocking mode");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of supported hardware formats */
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||
perror("SNDCTL_DSP_GETFMTS");
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't get audio format list");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
format = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!format && test_format;) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
@@ -255,50 +257,51 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
}
|
||||
if (format == 0) {
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
/* Set the audio format */
|
||||
value = format;
|
||||
if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
|
||||
if ( (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
|
||||
(value != format) ) {
|
||||
perror("SNDCTL_DSP_SETFMT");
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set audio format");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the number of channels of output */
|
||||
value = spec->channels;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
||||
value = this->spec.channels;
|
||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
||||
perror("SNDCTL_DSP_CHANNELS");
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Cannot set the number of channels");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
spec->channels = value;
|
||||
this->spec.channels = value;
|
||||
|
||||
/* Set the DSP frequency */
|
||||
value = spec->freq;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||
value = this->spec.freq;
|
||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||
perror("SNDCTL_DSP_SPEED");
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Couldn't set audio frequency");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
spec->freq = value;
|
||||
this->spec.freq = value;
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Determine the power of two of the fragment size */
|
||||
for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec);
|
||||
if ((0x01U << frag_spec) != spec->size) {
|
||||
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
|
||||
if ((0x01U << frag_spec) != this->spec.size) {
|
||||
DSP_CloseDevice(this);
|
||||
SDL_SetError("Fragment size must be a power of two");
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
||||
|
||||
@@ -307,13 +310,13 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
fprintf(stderr, "Requesting %d fragments of size %d\n",
|
||||
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
|
||||
#endif
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
||||
perror("SNDCTL_DSP_SETFRAGMENT");
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
{
|
||||
audio_buf_info info;
|
||||
ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
|
||||
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
|
||||
fprintf(stderr, "fragments = %d\n", info.fragments);
|
||||
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
|
||||
fprintf(stderr, "fragsize = %d\n", info.fragsize);
|
||||
@@ -322,19 +325,59 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
#endif
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
DSP_CloseAudio(this);
|
||||
return (-1);
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
DSP_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DSP_PlayDevice(_THIS)
|
||||
{
|
||||
const Uint8 *mixbuf = this->hidden->mixbuf;
|
||||
const int mixlen = this->hidden->mixlen;
|
||||
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
|
||||
perror("Audio write");
|
||||
this->enabled = 0;
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DSP_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static int
|
||||
DSP_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = DSP_DetectDevices;
|
||||
impl->GetDeviceName = DSP_GetDeviceName;
|
||||
impl->OpenDevice = DSP_OpenDevice;
|
||||
impl->PlayDevice = DSP_PlayDevice;
|
||||
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
||||
impl->CloseDevice = DSP_CloseDevice;
|
||||
impl->Deinitialize = DSP_Deinitialize;
|
||||
|
||||
build_device_lists();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap DSP_bootstrap = {
|
||||
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", DSP_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -34,22 +34,11 @@ struct SDL_PrivateAudioData
|
||||
/* The file descriptor for the audio device */
|
||||
int audio_fd;
|
||||
|
||||
/* The parent process id, to detect when application quits */
|
||||
pid_t parent;
|
||||
|
||||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
|
||||
#endif /* _SDL_dspaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -25,141 +25,27 @@
|
||||
|
||||
/* Output audio to nowhere... */
|
||||
|
||||
#include "SDL_rwops.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_dummyaudio.h"
|
||||
|
||||
/* The tag name used by DUMMY audio */
|
||||
#define DUMMYAUD_DRIVER_NAME "dummy"
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DUMMYAUD_WaitAudio(_THIS);
|
||||
static void DUMMYAUD_PlayAudio(_THIS);
|
||||
static Uint8 *DUMMYAUD_GetAudioBuf(_THIS);
|
||||
static void DUMMYAUD_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
static int
|
||||
DUMMYAUD_Available(void)
|
||||
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);
|
||||
return 1; /* always succeeds. */
|
||||
}
|
||||
|
||||
static void
|
||||
DUMMYAUD_DeleteDevice(SDL_AudioDevice * device)
|
||||
static int
|
||||
DUMMYAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
DUMMYAUD_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 = DUMMYAUD_OpenAudio;
|
||||
this->WaitAudio = DUMMYAUD_WaitAudio;
|
||||
this->PlayAudio = DUMMYAUD_PlayAudio;
|
||||
this->GetAudioBuf = DUMMYAUD_GetAudioBuf;
|
||||
this->CloseAudio = DUMMYAUD_CloseAudio;
|
||||
|
||||
this->free = DUMMYAUD_DeleteDevice;
|
||||
|
||||
return this;
|
||||
impl->OpenDevice = DUMMYAUD_OpenDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap DUMMYAUD_bootstrap = {
|
||||
DUMMYAUD_DRIVER_NAME, "SDL dummy audio driver",
|
||||
DUMMYAUD_Available, DUMMYAUD_CreateDevice
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
DUMMYAUD_WaitAudio(_THIS)
|
||||
{
|
||||
/* Don't block on first calls to simulate initial fragment filling. */
|
||||
if (this->hidden->initial_calls)
|
||||
this->hidden->initial_calls--;
|
||||
else
|
||||
SDL_Delay(this->hidden->write_delay);
|
||||
}
|
||||
|
||||
static void
|
||||
DUMMYAUD_PlayAudio(_THIS)
|
||||
{
|
||||
/* no-op...this is a null driver. */
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DUMMYAUD_GetAudioBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
DUMMYAUD_CloseAudio(_THIS)
|
||||
{
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
{
|
||||
float bytes_per_sec = 0.0f;
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
this->hidden->mixlen = spec->size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
|
||||
|
||||
bytes_per_sec = (float) (((spec->format & 0xFF) / 8) *
|
||||
spec->channels * spec->freq);
|
||||
|
||||
/*
|
||||
* We try to make this request more audio at the correct rate for
|
||||
* a given audio spec, so timing stays fairly faithful.
|
||||
* Also, we have it not block at all for the first two calls, so
|
||||
* it seems like we're filling two audio fragments right out of the
|
||||
* gate, like other SDL drivers tend to do.
|
||||
*/
|
||||
this->hidden->initial_calls = 2;
|
||||
this->hidden->write_delay =
|
||||
(Uint32) ((((float) spec->size) / bytes_per_sec) * 1000.0f);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_esdaudio.h"
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
|
||||
@@ -46,40 +45,34 @@
|
||||
/* The tag name used by ESD audio */
|
||||
#define ESD_DRIVER_NAME "esd"
|
||||
|
||||
/* Audio driver functions */
|
||||
static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void ESD_WaitAudio(_THIS);
|
||||
static void ESD_PlayAudio(_THIS);
|
||||
static Uint8 *ESD_GetAudioBuf(_THIS);
|
||||
static void ESD_CloseAudio(_THIS);
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
|
||||
|
||||
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
|
||||
static void *esd_handle = NULL;
|
||||
static int esd_loaded = 0;
|
||||
|
||||
static int (*SDL_NAME(esd_open_sound)) (const char *host);
|
||||
static int (*SDL_NAME(esd_close)) (int esd);
|
||||
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
|
||||
const char *host, const char *name);
|
||||
|
||||
#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} esd_functions[] = {
|
||||
{
|
||||
"esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, {
|
||||
"esd_close", (void **) &SDL_NAME(esd_close)}, {
|
||||
"esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},};
|
||||
SDL_ESD_SYM(esd_open_sound),
|
||||
SDL_ESD_SYM(esd_close),
|
||||
SDL_ESD_SYM(esd_play_stream),
|
||||
};
|
||||
#undef SDL_ESD_SYM
|
||||
|
||||
static void
|
||||
UnloadESDLibrary()
|
||||
{
|
||||
if (esd_loaded) {
|
||||
if (esd_handle != NULL) {
|
||||
SDL_UnloadObject(esd_handle);
|
||||
esd_handle = NULL;
|
||||
esd_loaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,17 +81,18 @@ LoadESDLibrary(void)
|
||||
{
|
||||
int i, retval = -1;
|
||||
|
||||
esd_handle = SDL_LoadObject(esd_library);
|
||||
if (esd_handle) {
|
||||
esd_loaded = 1;
|
||||
retval = 0;
|
||||
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
|
||||
*esd_functions[i].func =
|
||||
SDL_LoadFunction(esd_handle, esd_functions[i].name);
|
||||
if (!*esd_functions[i].func) {
|
||||
retval = -1;
|
||||
UnloadESDLibrary();
|
||||
break;
|
||||
if (esd_handle == NULL) {
|
||||
esd_handle = SDL_LoadObject(esd_library);
|
||||
if (esd_handle) {
|
||||
retval = 0;
|
||||
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
|
||||
*esd_functions[i].func =
|
||||
SDL_LoadFunction(esd_handle, esd_functions[i].name);
|
||||
if (!*esd_functions[i].func) {
|
||||
retval = -1;
|
||||
UnloadESDLibrary();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,78 +115,10 @@ LoadESDLibrary(void)
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
int connection;
|
||||
int available;
|
||||
|
||||
available = 0;
|
||||
if (LoadESDLibrary() < 0) {
|
||||
return available;
|
||||
}
|
||||
connection = SDL_NAME(esd_open_sound) (NULL);
|
||||
if (connection >= 0) {
|
||||
available = 1;
|
||||
SDL_NAME(esd_close) (connection);
|
||||
}
|
||||
UnloadESDLibrary();
|
||||
return (available);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
UnloadESDLibrary();
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
LoadESDLibrary();
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
audio_fd = -1;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = ESD_OpenAudio;
|
||||
this->WaitAudio = ESD_WaitAudio;
|
||||
this->PlayAudio = ESD_PlayAudio;
|
||||
this->GetAudioBuf = ESD_GetAudioBuf;
|
||||
this->CloseAudio = ESD_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap ESD_bootstrap = {
|
||||
ESD_DRIVER_NAME, "Enlightened Sound Daemon",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
ESD_WaitAudio(_THIS)
|
||||
ESD_WaitDevice(_THIS)
|
||||
{
|
||||
Sint32 ticks;
|
||||
|
||||
@@ -202,28 +128,31 @@ ESD_WaitAudio(_THIS)
|
||||
/* Note that this only works with thread implementations
|
||||
that use a different process id for each thread.
|
||||
*/
|
||||
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
|
||||
if (kill(parent, 0) < 0) {
|
||||
/* Check every 10 loops */
|
||||
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
|
||||
if (kill(this->hidden->parent, 0) < 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use timer for general audio synchronization */
|
||||
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
|
||||
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
|
||||
if (ticks > 0) {
|
||||
SDL_Delay(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ESD_PlayAudio(_THIS)
|
||||
ESD_PlayDevice(_THIS)
|
||||
{
|
||||
int written;
|
||||
int written = 0;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||
do {
|
||||
written = write(audio_fd, mixbuf, mixlen);
|
||||
written = write(this->hidden->audio_fd,
|
||||
this->hidden->mixbuf,
|
||||
this->hidden->mixlen);
|
||||
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
|
||||
SDL_Delay(1); /* Let a little CPU time go by */
|
||||
}
|
||||
@@ -232,7 +161,7 @@ ESD_PlayAudio(_THIS)
|
||||
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
|
||||
|
||||
/* Set the next write frame */
|
||||
next_frame += frame_ticks;
|
||||
this->hidden->next_frame += this->hidden->frame_ticks;
|
||||
|
||||
/* If we couldn't write, assume fatal error for now */
|
||||
if (written < 0) {
|
||||
@@ -241,21 +170,26 @@ ESD_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
ESD_GetAudioBuf(_THIS)
|
||||
ESD_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (mixbuf);
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
ESD_CloseAudio(_THIS)
|
||||
ESD_CloseDevice(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (audio_fd >= 0) {
|
||||
SDL_NAME(esd_close) (audio_fd);
|
||||
audio_fd = -1;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->audio_fd >= 0) {
|
||||
SDL_NAME(esd_close) (this->hidden->audio_fd);
|
||||
this->hidden->audio_fd = -1;
|
||||
}
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,59 +219,135 @@ get_progname(void)
|
||||
return (progname);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
ESD_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
esd_format_t format;
|
||||
esd_format_t format = (ESD_STREAM | ESD_PLAY);
|
||||
SDL_AudioFormat test_format = 0;
|
||||
int found = 0;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
this->hidden->audio_fd = -1;
|
||||
|
||||
/* Convert audio spec to the ESD audio format */
|
||||
format = (ESD_STREAM | ESD_PLAY);
|
||||
switch (spec->format & 0xFF) {
|
||||
case 8:
|
||||
format |= ESD_BITS8;
|
||||
break;
|
||||
case 16:
|
||||
format |= ESD_BITS16;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unsupported ESD audio format");
|
||||
return (-1);
|
||||
/* Try for a closest match on audio format */
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!found && test_format; test_format = SDL_NextAudioFormat()) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
#endif
|
||||
found = 1;
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
format |= ESD_BITS8;
|
||||
break;
|
||||
case AUDIO_S16SYS:
|
||||
format |= ESD_BITS16;
|
||||
break;
|
||||
default:
|
||||
found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (spec->channels == 1) {
|
||||
|
||||
if (!found) {
|
||||
ESD_CloseDevice(this);
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->spec.channels == 1) {
|
||||
format |= ESD_MONO;
|
||||
} else {
|
||||
format |= ESD_STEREO;
|
||||
}
|
||||
#if 0
|
||||
spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
|
||||
this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
|
||||
#endif
|
||||
|
||||
/* Open a connection to the ESD audio server */
|
||||
audio_fd =
|
||||
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
|
||||
if (audio_fd < 0) {
|
||||
this->hidden->audio_fd =
|
||||
SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname());
|
||||
|
||||
if (this->hidden->audio_fd < 0) {
|
||||
ESD_CloseDevice(this);
|
||||
SDL_SetError("Couldn't open ESD connection");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
|
||||
next_frame = SDL_GetTicks() + frame_ticks;
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
|
||||
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
return (-1);
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
ESD_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
this->hidden->parent = getpid();
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ESD_Deinitialize(void)
|
||||
{
|
||||
UnloadESDLibrary();
|
||||
}
|
||||
|
||||
static int
|
||||
ESD_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
if (LoadESDLibrary() < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
int connection = 0;
|
||||
|
||||
/* Don't start ESD if it's not running */
|
||||
if (SDL_getenv("ESD_NO_SPAWN") == NULL) {
|
||||
SDL_putenv("ESD_NO_SPAWN=1");
|
||||
}
|
||||
|
||||
connection = SDL_NAME(esd_open_sound) (NULL);
|
||||
if (connection < 0) {
|
||||
UnloadESDLibrary();
|
||||
SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
|
||||
return 0;
|
||||
}
|
||||
SDL_NAME(esd_close) (connection);
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = ESD_OpenDevice;
|
||||
impl->PlayDevice = ESD_PlayDevice;
|
||||
impl->WaitDevice = ESD_WaitDevice;
|
||||
impl->GetDeviceBuf = ESD_GetDeviceBuf;
|
||||
impl->CloseDevice = ESD_CloseDevice;
|
||||
impl->Deinitialize = ESD_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap ESD_bootstrap = {
|
||||
ESD_DRIVER_NAME, "Enlightened Sound Daemon", ESD_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -47,13 +47,5 @@ struct SDL_PrivateAudioData
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
|
||||
#endif /* _SDL_esdaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#include "SDL_audio.h"
|
||||
@@ -28,79 +29,233 @@
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_coreaudio.h"
|
||||
|
||||
#define DEBUG_COREAUDIO 0
|
||||
|
||||
/* Audio driver functions */
|
||||
|
||||
static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Core_WaitAudio(_THIS);
|
||||
static void Core_PlayAudio(_THIS);
|
||||
static Uint8 *Core_GetAudioBuf(_THIS);
|
||||
static void Core_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
typedef struct COREAUDIO_DeviceList
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
AudioDeviceID id;
|
||||
const char *name;
|
||||
} COREAUDIO_DeviceList;
|
||||
|
||||
static COREAUDIO_DeviceList *inputDevices = NULL;
|
||||
static int inputDeviceCount = 0;
|
||||
static COREAUDIO_DeviceList *outputDevices = NULL;
|
||||
static int outputDeviceCount = 0;
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
free_device_list(COREAUDIO_DeviceList **devices, int *devCount)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
if (*devices) {
|
||||
int i = *devCount;
|
||||
while (i--)
|
||||
SDL_free((void *) (*devices)[i].name);
|
||||
SDL_free(*devices);
|
||||
*devices = NULL;
|
||||
}
|
||||
*devCount = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
static void
|
||||
build_device_list(int iscapture, COREAUDIO_DeviceList **devices, int *devCount)
|
||||
{
|
||||
Boolean outWritable = 0;
|
||||
OSStatus result = noErr;
|
||||
UInt32 size = 0;
|
||||
AudioDeviceID *devs = NULL;
|
||||
UInt32 i = 0;
|
||||
UInt32 max = 0;
|
||||
|
||||
free_device_list(devices, devCount);
|
||||
|
||||
result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
|
||||
&size, &outWritable);
|
||||
|
||||
if (result != kAudioHardwareNoError)
|
||||
return;
|
||||
|
||||
devs = (AudioDeviceID *) alloca(size);
|
||||
if (devs == NULL)
|
||||
return;
|
||||
|
||||
max = size / sizeof (AudioDeviceID);
|
||||
*devices = (COREAUDIO_DeviceList *) SDL_malloc(max * sizeof (**devices));
|
||||
if (*devices == NULL)
|
||||
return;
|
||||
|
||||
result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
|
||||
&size, devs);
|
||||
if (result != kAudioHardwareNoError)
|
||||
return;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
CFStringRef cfstr = NULL;
|
||||
char *ptr = NULL;
|
||||
AudioDeviceID dev = devs[i];
|
||||
AudioBufferList *buflist = NULL;
|
||||
int usable = 0;
|
||||
CFIndex len = 0;
|
||||
|
||||
result = AudioDeviceGetPropertyInfo(dev, 0, iscapture,
|
||||
kAudioDevicePropertyStreamConfiguration,
|
||||
&size, &outWritable);
|
||||
if (result != noErr)
|
||||
continue;
|
||||
|
||||
buflist = (AudioBufferList *) SDL_malloc(size);
|
||||
if (buflist == NULL)
|
||||
continue;
|
||||
|
||||
result = AudioDeviceGetProperty(dev, 0, iscapture,
|
||||
kAudioDevicePropertyStreamConfiguration,
|
||||
&size, buflist);
|
||||
|
||||
if (result == noErr) {
|
||||
UInt32 j;
|
||||
for (j = 0; j < buflist->mNumberBuffers; j++) {
|
||||
if (buflist->mBuffers[j].mNumberChannels > 0) {
|
||||
usable = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(buflist);
|
||||
|
||||
if (!usable)
|
||||
continue;
|
||||
|
||||
size = sizeof (CFStringRef);
|
||||
result = AudioDeviceGetProperty(dev, 0, iscapture,
|
||||
kAudioObjectPropertyName,
|
||||
&size, &cfstr);
|
||||
|
||||
if (result != kAudioHardwareNoError)
|
||||
continue;
|
||||
|
||||
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
ptr = (char *) SDL_malloc(len + 1);
|
||||
usable = ( (ptr != NULL) &&
|
||||
(CFStringGetCString(cfstr,ptr,len+1,kCFStringEncodingUTF8)) );
|
||||
|
||||
CFRelease(cfstr);
|
||||
|
||||
if (usable) {
|
||||
len = strlen(ptr);
|
||||
/* Some devices have whitespace at the end...trim it. */
|
||||
while ((len > 0) && (ptr[len-1] == ' ')) {
|
||||
len--;
|
||||
}
|
||||
usable = (len > 0);
|
||||
}
|
||||
|
||||
if (!usable) {
|
||||
SDL_free(ptr);
|
||||
} else {
|
||||
ptr[len] = '\0';
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
|
||||
((iscapture) ? "capture" : "output"),
|
||||
(int) *devCount, ptr, (int) dev);
|
||||
#endif
|
||||
|
||||
(*devices)[*devCount].id = dev;
|
||||
(*devices)[*devCount].name = ptr;
|
||||
(*devCount)++;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Core_OpenAudio;
|
||||
this->WaitAudio = Core_WaitAudio;
|
||||
this->PlayAudio = Core_PlayAudio;
|
||||
this->GetAudioBuf = Core_GetAudioBuf;
|
||||
this->CloseAudio = Core_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "Mac OS X CoreAudio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
static inline void
|
||||
build_device_lists(void)
|
||||
{
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
free_device_lists(void)
|
||||
{
|
||||
free_device_list(&outputDevices, &outputDeviceCount);
|
||||
free_device_list(&inputDevices, &inputDeviceCount);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
find_device_id(const char *devname, int iscapture, AudioDeviceID *id)
|
||||
{
|
||||
int i = ((iscapture) ? inputDeviceCount : outputDeviceCount);
|
||||
COREAUDIO_DeviceList *devs = ((iscapture) ? inputDevices : outputDevices);
|
||||
while (i--) {
|
||||
if (SDL_strcmp(devname, devs->name) == 0) {
|
||||
*id = devs->id;
|
||||
return 1;
|
||||
}
|
||||
devs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
COREAUDIO_DetectDevices(int iscapture)
|
||||
{
|
||||
if (iscapture) {
|
||||
build_device_list(1, &inputDevices, &inputDeviceCount);
|
||||
return inputDeviceCount;
|
||||
} else {
|
||||
build_device_list(0, &outputDevices, &outputDeviceCount);
|
||||
return outputDeviceCount;
|
||||
}
|
||||
|
||||
return 0; /* shouldn't ever hit 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();
|
||||
}
|
||||
|
||||
|
||||
/* The CoreAudio callback */
|
||||
static OSStatus
|
||||
audioCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
outputCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp * inTimeStamp,
|
||||
UInt32 inBusNumber, AudioBuffer * ioData)
|
||||
UInt32 inBusNumber, UInt32 inNumberFrames,
|
||||
AudioBufferList *ioDataList)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
|
||||
AudioBuffer *ioData = &ioDataList->mBuffers[0];
|
||||
UInt32 remaining, len;
|
||||
void *ptr;
|
||||
|
||||
/* Is there ever more than one buffer, and what do you do with it? */
|
||||
if (ioDataList->mNumberBuffers != 1) {
|
||||
return noErr;
|
||||
}
|
||||
|
||||
/* Only do anything if audio is enabled and not paused */
|
||||
if (!this->enabled || this->paused) {
|
||||
SDL_memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
|
||||
@@ -118,109 +273,251 @@ audioCallback(void *inRefCon,
|
||||
remaining = ioData->mDataByteSize;
|
||||
ptr = ioData->mData;
|
||||
while (remaining > 0) {
|
||||
if (bufferOffset >= bufferSize) {
|
||||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
||||
/* Generate the data */
|
||||
SDL_memset(buffer, this->spec.silence, bufferSize);
|
||||
SDL_memset(this->hidden->buffer, this->spec.silence,
|
||||
this->hidden->bufferSize);
|
||||
SDL_mutexP(this->mixer_lock);
|
||||
(*this->spec.callback) (this->spec.userdata, buffer, bufferSize);
|
||||
(*this->spec.callback) (this->spec.userdata, this->hidden->buffer,
|
||||
this->hidden->bufferSize);
|
||||
SDL_mutexV(this->mixer_lock);
|
||||
bufferOffset = 0;
|
||||
this->hidden->bufferOffset = 0;
|
||||
}
|
||||
|
||||
len = bufferSize - bufferOffset;
|
||||
len = this->hidden->bufferSize - this->hidden->bufferOffset;
|
||||
if (len > remaining)
|
||||
len = remaining;
|
||||
SDL_memcpy(ptr, (char *) buffer + bufferOffset, len);
|
||||
SDL_memcpy(ptr,
|
||||
(char *) this->hidden->buffer + this->hidden->bufferOffset,
|
||||
len);
|
||||
ptr = (char *) ptr + len;
|
||||
remaining -= len;
|
||||
bufferOffset += len;
|
||||
this->hidden->bufferOffset += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dummy functions -- we don't use thread-based audio */
|
||||
void
|
||||
Core_WaitAudio(_THIS)
|
||||
static OSStatus
|
||||
inputCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp * inTimeStamp,
|
||||
UInt32 inBusNumber, UInt32 inNumberFrames,
|
||||
AudioBufferList *ioData)
|
||||
{
|
||||
return;
|
||||
//err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer);
|
||||
// !!! FIXME: write me!
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void
|
||||
Core_PlayAudio(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Uint8 *
|
||||
Core_GetAudioBuf(_THIS)
|
||||
static void
|
||||
COREAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
if (this->hidden != NULL) {
|
||||
OSStatus result = noErr;
|
||||
AURenderCallbackStruct callback;
|
||||
const AudioUnitElement output_bus = 0;
|
||||
const AudioUnitElement input_bus = 1;
|
||||
const int iscapture = this->iscapture;
|
||||
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
|
||||
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
|
||||
kAudioUnitScope_Input);
|
||||
|
||||
void
|
||||
Core_CloseAudio(_THIS)
|
||||
{
|
||||
OSStatus result;
|
||||
struct AudioUnitInputCallback callback;
|
||||
/* stop processing the audio unit */
|
||||
result = AudioOutputUnitStop(this->hidden->audioUnit);
|
||||
|
||||
/* stop processing the audio unit */
|
||||
result = AudioOutputUnitStop(outputAudioUnit);
|
||||
if (result != noErr) {
|
||||
SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
|
||||
return;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Remove the input callback */
|
||||
callback.inputProc = 0;
|
||||
callback.inputProcRefCon = 0;
|
||||
result = AudioUnitSetProperty(outputAudioUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0, &callback, sizeof(callback));
|
||||
if (result != noErr) {
|
||||
SDL_SetError
|
||||
("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
|
||||
return;
|
||||
}
|
||||
|
||||
result = CloseComponent(outputAudioUnit);
|
||||
if (result != noErr) {
|
||||
SDL_SetError("Core_CloseAudio: CloseComponent");
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_RESULT(msg) \
|
||||
if (result != noErr) { \
|
||||
COREAUDIO_CloseDevice(this); \
|
||||
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
||||
return -1; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
static int
|
||||
find_device_by_name(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
AudioDeviceID devid = 0;
|
||||
OSStatus result = noErr;
|
||||
UInt32 size = 0;
|
||||
UInt32 alive = 0;
|
||||
pid_t pid = 0;
|
||||
|
||||
int
|
||||
Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
if (devname == NULL) {
|
||||
size = sizeof (AudioDeviceID);
|
||||
const AudioHardwarePropertyID propid =
|
||||
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
|
||||
kAudioHardwarePropertyDefaultOutputDevice);
|
||||
|
||||
result = AudioHardwareGetProperty(propid, &size, &devid);
|
||||
CHECK_RESULT("AudioHardwareGetProperty (default device)");
|
||||
} else {
|
||||
if (!find_device_id(devname, iscapture, &devid)) {
|
||||
SDL_SetError("CoreAudio: No such audio device.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof (alive);
|
||||
result = AudioDeviceGetProperty(devid, 0, iscapture,
|
||||
kAudioDevicePropertyDeviceIsAlive,
|
||||
&size, &alive);
|
||||
CHECK_RESULT("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
|
||||
|
||||
if (!alive) {
|
||||
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = sizeof (pid);
|
||||
result = AudioDeviceGetProperty(devid, 0, iscapture,
|
||||
kAudioDevicePropertyHogMode, &size, &pid);
|
||||
|
||||
/* some devices don't support this property, so errors are fine here. */
|
||||
if ((result == noErr) && (pid != -1)) {
|
||||
SDL_SetError("CoreAudio: requested device is being hogged.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->hidden->deviceID = devid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
prepare_audiounit(_THIS, const char *devname, int iscapture,
|
||||
const AudioStreamBasicDescription *strdesc)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
Component comp;
|
||||
AURenderCallbackStruct callback;
|
||||
ComponentDescription desc;
|
||||
struct AudioUnitInputCallback callback;
|
||||
Component comp = NULL;
|
||||
int use_system_device = 0;
|
||||
UInt32 enableIO = 0;
|
||||
const AudioUnitElement output_bus = 0;
|
||||
const AudioUnitElement input_bus = 1;
|
||||
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
|
||||
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
|
||||
kAudioUnitScope_Input);
|
||||
|
||||
if (!find_device_by_name(this, devname, iscapture)) {
|
||||
SDL_SetError("Couldn't find requested CoreAudio device");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_memset(&desc, '\0', sizeof(ComponentDescription));
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
comp = FindNextComponent(NULL, &desc);
|
||||
if (comp == NULL) {
|
||||
SDL_SetError("Couldn't find requested CoreAudio component");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open & initialize the audio unit */
|
||||
result = OpenAComponent(comp, &this->hidden->audioUnit);
|
||||
CHECK_RESULT("OpenAComponent");
|
||||
|
||||
// !!! FIXME: this is wrong?
|
||||
enableIO = ((iscapture) ? 1 : 0);
|
||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||
kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitScope_Input, input_bus,
|
||||
&enableIO, sizeof (enableIO));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO input)");
|
||||
|
||||
// !!! FIXME: this is wrong?
|
||||
enableIO = ((iscapture) ? 0 : 1);
|
||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||
kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitScope_Output, output_bus,
|
||||
&enableIO, sizeof (enableIO));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_EnableIO output)");
|
||||
|
||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||
kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioUnitScope_Global, 0,
|
||||
&this->hidden->deviceID,
|
||||
sizeof (AudioDeviceID));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
|
||||
|
||||
/* Set the data format of the audio unit. */
|
||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
scope, bus, strdesc, sizeof (*strdesc));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
|
||||
|
||||
/* Set the audio callback */
|
||||
SDL_memset(&callback, '\0', sizeof (AURenderCallbackStruct));
|
||||
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
|
||||
callback.inputProcRefCon = this;
|
||||
result = AudioUnitSetProperty(this->hidden->audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
scope, bus, &callback, sizeof (callback));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate a sample buffer */
|
||||
this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
|
||||
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
|
||||
|
||||
result = AudioUnitInitialize(this->hidden->audioUnit);
|
||||
CHECK_RESULT("AudioUnitInitialize");
|
||||
|
||||
/* Finally, start processing of the audio unit */
|
||||
result = AudioOutputUnitStart(this->hidden->audioUnit);
|
||||
CHECK_RESULT("AudioOutputUnitStart");
|
||||
|
||||
/* We're running! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
AudioStreamBasicDescription strdesc;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
int valid_datatype = 0;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Setup a AudioStreamBasicDescription with the requested format */
|
||||
memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
|
||||
SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
|
||||
strdesc.mFormatID = kAudioFormatLinearPCM;
|
||||
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
strdesc.mChannelsPerFrame = spec->channels;
|
||||
strdesc.mSampleRate = spec->freq;
|
||||
strdesc.mChannelsPerFrame = this->spec.channels;
|
||||
strdesc.mSampleRate = this->spec.freq;
|
||||
strdesc.mFramesPerPacket = 1;
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
/* Just a list of valid SDL formats, so people don't pass junk here. */
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
@@ -234,13 +531,13 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
case AUDIO_F32LSB:
|
||||
case AUDIO_F32MSB:
|
||||
valid_datatype = 1;
|
||||
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format);
|
||||
if (SDL_AUDIO_ISBIGENDIAN(spec->format))
|
||||
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
|
||||
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
|
||||
if (SDL_AUDIO_ISFLOAT(spec->format))
|
||||
if (SDL_AUDIO_ISFLOAT(this->spec.format))
|
||||
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
|
||||
else if (SDL_AUDIO_ISSIGNED(spec->format))
|
||||
else if (SDL_AUDIO_ISSIGNED(this->spec.format))
|
||||
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
}
|
||||
@@ -248,7 +545,7 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
if (!valid_datatype) { /* shouldn't happen, but just in case... */
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strdesc.mBytesPerFrame =
|
||||
@@ -256,52 +553,31 @@ Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
strdesc.mBytesPerPacket =
|
||||
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
|
||||
|
||||
/* Locate the default output audio unit */
|
||||
memset(&desc, '\0', sizeof(ComponentDescription));
|
||||
desc.componentType = kAudioUnitComponentType;
|
||||
desc.componentSubType = kAudioUnitSubType_Output;
|
||||
desc.componentManufacturer = kAudioUnitID_DefaultOutput;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
comp = FindNextComponent(NULL, &desc);
|
||||
if (comp == NULL) {
|
||||
SDL_SetError
|
||||
("Failed to start CoreAudio: FindNextComponent returned NULL");
|
||||
return -1;
|
||||
if (!prepare_audiounit(this, devname, iscapture, &strdesc)) {
|
||||
return 0; /* prepare_audiounit() will call SDL_SetError()... */
|
||||
}
|
||||
|
||||
/* Open & initialize the default output audio unit */
|
||||
result = OpenAComponent(comp, &outputAudioUnit);
|
||||
CHECK_RESULT("OpenAComponent")
|
||||
result = AudioUnitInitialize(outputAudioUnit);
|
||||
CHECK_RESULT("AudioUnitInitialize")
|
||||
/* Set the input format of the audio unit. */
|
||||
result = AudioUnitSetProperty(outputAudioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0, &strdesc, sizeof(strdesc));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
|
||||
/* Set the audio callback */
|
||||
callback.inputProc = audioCallback;
|
||||
callback.inputProcRefCon = this;
|
||||
result = AudioUnitSetProperty(outputAudioUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0, &callback, sizeof(callback));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
/* Allocate a sample buffer */
|
||||
bufferOffset = bufferSize = this->spec.size;
|
||||
buffer = SDL_malloc(bufferSize);
|
||||
|
||||
/* Finally, start processing of the audio unit */
|
||||
result = AudioOutputUnitStart(outputAudioUnit);
|
||||
CHECK_RESULT("AudioOutputUnitStart")
|
||||
/* We're running! */
|
||||
return (1);
|
||||
return 1; /* good to go. */
|
||||
}
|
||||
|
||||
static int
|
||||
COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = COREAUDIO_DetectDevices;
|
||||
impl->GetDeviceName = COREAUDIO_GetDeviceName;
|
||||
impl->OpenDevice = COREAUDIO_OpenDevice;
|
||||
impl->CloseDevice = COREAUDIO_CloseDevice;
|
||||
impl->Deinitialize = COREAUDIO_Deinitialize;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
|
||||
build_device_lists(); /* do an initial check for devices... */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "Mac OS X CoreAudio", COREAUDIO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,22 +26,17 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
AudioUnit outputAudioUnit;
|
||||
AudioUnit audioUnit;
|
||||
void *buffer;
|
||||
UInt32 bufferOffset;
|
||||
UInt32 bufferSize;
|
||||
AudioDeviceID deviceID;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define outputAudioUnit (this->hidden->outputAudioUnit)
|
||||
#define buffer (this->hidden->buffer)
|
||||
#define bufferOffset (this->hidden->bufferOffset)
|
||||
#define bufferSize (this->hidden->bufferSize)
|
||||
|
||||
#endif /* _SDL_coreaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,11 +21,16 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
/* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
# define SDL_MACOS_NAME "Mac OS X"
|
||||
# include <Carbon/Carbon.h>
|
||||
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
|
||||
# define SDL_MACOS_NAME "Mac OS 9"
|
||||
# include <Carbon.h>
|
||||
#else
|
||||
# define SDL_MACOS_NAME "Mac OS 9"
|
||||
# include <Sound.h> /* SoundManager interface */
|
||||
# include <Gestalt.h>
|
||||
# include <DriverServices.h>
|
||||
@@ -45,72 +50,6 @@
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_romaudio.h"
|
||||
|
||||
/* Audio driver functions */
|
||||
|
||||
static void Mac_CloseAudio(_THIS);
|
||||
static int Mac_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mac_LockAudio(_THIS);
|
||||
static void Mac_UnlockAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Mac_OpenAudio;
|
||||
this->CloseAudio = Mac_CloseAudio;
|
||||
this->LockAudio = Mac_LockAudio;
|
||||
this->UnlockAudio = Mac_UnlockAudio;
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
#ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
|
||||
this->LockAudio = NULL;
|
||||
this->UnlockAudio = NULL;
|
||||
#endif
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap SNDMGR_bootstrap = {
|
||||
"sndmgr", "MacOS SoundManager 3.0",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
|
||||
/* This works correctly on Mac OS X */
|
||||
|
||||
#pragma options align=power
|
||||
|
||||
static volatile SInt32 audio_is_locked = 0;
|
||||
@@ -121,6 +60,7 @@ static volatile UInt32 running = 0;
|
||||
static CmpSoundHeader header;
|
||||
static volatile Uint32 fill_me = 0;
|
||||
|
||||
|
||||
static void
|
||||
mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
|
||||
{
|
||||
@@ -150,13 +90,13 @@ mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
|
||||
}
|
||||
|
||||
static void
|
||||
Mac_LockAudio(_THIS)
|
||||
SNDMGR_LockDevice(_THIS)
|
||||
{
|
||||
IncrementAtomic((SInt32 *) & audio_is_locked);
|
||||
}
|
||||
|
||||
static void
|
||||
Mac_UnlockAudio(_THIS)
|
||||
SNDMGR_UnlockDevice(_THIS)
|
||||
{
|
||||
SInt32 oldval;
|
||||
|
||||
@@ -198,7 +138,7 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
|
||||
cmd.param2 = (long) &header;
|
||||
SndDoCommand(chan, &cmd, 0);
|
||||
|
||||
memset(buffer[fill_me], 0, audio->spec.size);
|
||||
SDL_memset(buffer[fill_me], 0, audio->spec.size);
|
||||
|
||||
/*
|
||||
* if audio device isn't locked, mix the next buffer to be queued in
|
||||
@@ -219,14 +159,25 @@ callBackProc(SndChannel * chan, SndCommand * cmd_passed)
|
||||
}
|
||||
|
||||
static int
|
||||
Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SNDMGR_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
|
||||
SDL_AudioSpec *spec = &this->spec;
|
||||
SndChannelPtr channel = NULL;
|
||||
SndCallBackUPP callback;
|
||||
int sample_bits;
|
||||
int i;
|
||||
long initOptions;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* !!! FIXME: iterate through format matrix... */
|
||||
/* Very few conversions are required, but... */
|
||||
switch (spec->format) {
|
||||
case AUDIO_S8:
|
||||
@@ -242,10 +193,10 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
spec->format = AUDIO_F32MSB;
|
||||
break;
|
||||
}
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* initialize bufferCmd header */
|
||||
memset(&header, 0, sizeof(header));
|
||||
SDL_memset(&header, 0, sizeof(header));
|
||||
callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
|
||||
sample_bits = spec->size / spec->samples / spec->channels * 8;
|
||||
|
||||
@@ -278,20 +229,23 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* allocate 2 buffers */
|
||||
for (i = 0; i < 2; i++) {
|
||||
buffer[i] = (UInt8 *) malloc(sizeof(UInt8) * spec->size);
|
||||
buffer[i] = (UInt8 *) SDL_malloc(sizeof(UInt8) * spec->size);
|
||||
if (buffer[i] == NULL) {
|
||||
SNDMGR_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
memset(buffer[i], 0, spec->size);
|
||||
SDL_memset(buffer[i], 0, spec->size);
|
||||
}
|
||||
|
||||
/* Create the sound manager channel */
|
||||
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
|
||||
if (channel == NULL) {
|
||||
SNDMGR_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
this->hidden->channel = channel;
|
||||
if (spec->channels >= 2) {
|
||||
initOptions = initStereo;
|
||||
} else {
|
||||
@@ -300,10 +254,9 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
channel->userInfo = (long) this;
|
||||
channel->qLength = 128;
|
||||
if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
|
||||
SNDMGR_CloseDevice(this);
|
||||
SDL_SetError("Unable to create audio channel");
|
||||
SDL_free(channel);
|
||||
channel = NULL;
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* start playback */
|
||||
@@ -319,16 +272,15 @@ Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static void
|
||||
Mac_CloseAudio(_THIS)
|
||||
SNDMGR_CloseDevice(_THIS)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
running = 0;
|
||||
|
||||
if (channel) {
|
||||
SndDisposeChannel(channel, true);
|
||||
channel = NULL;
|
||||
if (this->hidden->channel) {
|
||||
SndDisposeChannel(this->hidden->channel, true);
|
||||
this->hidden->channel = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
@@ -337,193 +289,31 @@ Mac_CloseAudio(_THIS)
|
||||
buffer[i] = NULL;
|
||||
}
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
|
||||
#else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
|
||||
|
||||
static void
|
||||
Mac_LockAudio(_THIS)
|
||||
static int
|
||||
SNDMGR_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* no-op. */
|
||||
}
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = SNDMGR_OpenDevice;
|
||||
impl->CloseDevice = SNDMGR_CloseDevice;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
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 */ ;
|
||||
}
|
||||
/* Mac OS X uses threaded audio, so normal thread code is okay */
|
||||
#ifndef __MACOSX__
|
||||
impl->LockDevice = SNDMGR_LockDevice;
|
||||
impl->UnlockDevice = SNDMGR_UnlockDevice;
|
||||
impl->SkipMixerLock = 1;
|
||||
#endif
|
||||
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
|
||||
DoubleBufferAudio_Available(void)
|
||||
{
|
||||
int available;
|
||||
NumVersion sndversion;
|
||||
long response;
|
||||
|
||||
available = 0;
|
||||
sndversion = SndSoundManagerVersion();
|
||||
if (sndversion.majorRev >= 3) {
|
||||
if (Gestalt(gestaltSoundAttr, &response) == noErr) {
|
||||
if ((response & (1 << gestaltSndPlayDoubleBuffer))) {
|
||||
available = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Gestalt(gestaltSoundAttr, &response) == noErr) {
|
||||
if ((response & (1 << gestaltHasASC))) {
|
||||
available = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (available);
|
||||
}
|
||||
|
||||
static void
|
||||
Mac_CloseAudio(_THIS)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (channel != NULL) {
|
||||
/* Clean up the audio channel */
|
||||
SndDisposeChannel(channel, true);
|
||||
channel = NULL;
|
||||
}
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (audio_buf[i]) {
|
||||
SDL_free(audio_buf[i]);
|
||||
audio_buf[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
{
|
||||
SndDoubleBufferHeader2 audio_dbh;
|
||||
int i;
|
||||
long initOptions;
|
||||
int sample_bits;
|
||||
SndDoubleBackUPP doubleBackProc;
|
||||
|
||||
/* Check to make sure double-buffered audio is available */
|
||||
if (!DoubleBufferAudio_Available()) {
|
||||
SDL_SetError("Sound manager doesn't support double-buffering");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Very few conversions are required, but... */
|
||||
switch (spec->format) {
|
||||
case AUDIO_S8:
|
||||
spec->format = AUDIO_U8;
|
||||
break;
|
||||
case AUDIO_U16LSB:
|
||||
spec->format = AUDIO_S16LSB;
|
||||
break;
|
||||
case AUDIO_U16MSB:
|
||||
spec->format = AUDIO_S16MSB;
|
||||
break;
|
||||
}
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
/* initialize the double-back header */
|
||||
SDL_memset(&audio_dbh, 0, sizeof(audio_dbh));
|
||||
doubleBackProc = NewSndDoubleBackProc(sndDoubleBackProc);
|
||||
sample_bits = spec->size / spec->samples / spec->channels * 8;
|
||||
|
||||
audio_dbh.dbhNumChannels = spec->channels;
|
||||
audio_dbh.dbhSampleSize = sample_bits;
|
||||
audio_dbh.dbhCompressionID = 0;
|
||||
audio_dbh.dbhPacketSize = 0;
|
||||
audio_dbh.dbhSampleRate = spec->freq << 16;
|
||||
audio_dbh.dbhDoubleBack = doubleBackProc;
|
||||
audio_dbh.dbhFormat = 0;
|
||||
|
||||
/* Note that we install the 16bitLittleEndian Converter if needed. */
|
||||
if (spec->format == 0x8010) {
|
||||
audio_dbh.dbhCompressionID = fixedCompression;
|
||||
audio_dbh.dbhFormat = k16BitLittleEndianFormat;
|
||||
}
|
||||
|
||||
/* allocate the 2 double-back buffers */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
audio_buf[i] = SDL_calloc(1, sizeof(SndDoubleBuffer) + spec->size);
|
||||
if (audio_buf[i] == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return (-1);
|
||||
}
|
||||
audio_buf[i]->dbNumFrames = spec->samples;
|
||||
audio_buf[i]->dbFlags = dbBufferReady;
|
||||
audio_buf[i]->dbUserInfo[0] = (long) this;
|
||||
audio_dbh.dbhBufferPtr[i] = audio_buf[i];
|
||||
}
|
||||
|
||||
/* Create the sound manager channel */
|
||||
channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
|
||||
if (channel == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return (-1);
|
||||
}
|
||||
if (spec->channels >= 2) {
|
||||
initOptions = initStereo;
|
||||
} else {
|
||||
initOptions = initMono;
|
||||
}
|
||||
channel->userInfo = 0;
|
||||
channel->qLength = 128;
|
||||
if (SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr) {
|
||||
SDL_SetError("Unable to create audio channel");
|
||||
SDL_free(channel);
|
||||
channel = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Start playback */
|
||||
if (SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr) & audio_dbh)
|
||||
!= noErr) {
|
||||
SDL_SetError("Unable to play double buffered audio");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
|
||||
AudioBootStrap SNDMGR_bootstrap = {
|
||||
"sndmgr", SDL_MACOS_NAME " SoundManager", SNDMGR_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,27 +26,14 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* This is Ryan's improved MacOS sound code, with locking support */
|
||||
#define USE_RYANS_SOUNDCODE
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* Sound manager audio channel */
|
||||
SndChannelPtr channel;
|
||||
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
|
||||
/* FIXME: Add Ryan's static data here */
|
||||
#else
|
||||
/* Double buffering variables */
|
||||
SndDoubleBufferPtr audio_buf[2];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define channel (this->hidden->channel)
|
||||
#define audio_buf (this->hidden->audio_buf)
|
||||
|
||||
#endif /* _SDL_romaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -61,105 +61,8 @@
|
||||
|
||||
static unsigned long cookie_snd, cookie_mch;
|
||||
|
||||
/*--- Audio driver functions ---*/
|
||||
|
||||
static void Mint_CloseAudio(_THIS);
|
||||
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_LockAudio(_THIS);
|
||||
static void Mint_UnlockAudio(_THIS);
|
||||
|
||||
/* To check/init hardware audio */
|
||||
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
|
||||
|
||||
/*--- Audio driver bootstrap functions ---*/
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
|
||||
|
||||
/* Check if user asked a different audio driver */
|
||||
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cookie _MCH present ? if not, assume ST machine */
|
||||
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
|
||||
cookie_mch = MCH_ST;
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 8 bits audio */
|
||||
if ((cookie_snd & SND_8BIT) == 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (cookie_snd & SND_16BIT) {
|
||||
if (Locksnd() != 1) {
|
||||
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Mint_OpenAudio;
|
||||
this->CloseAudio = Mint_CloseAudio;
|
||||
this->LockAudio = Mint_LockAudio;
|
||||
this->UnlockAudio = Mint_UnlockAudio;
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
static void
|
||||
Mint_LockAudio(_THIS)
|
||||
MINTDMA8_LockDevice(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
|
||||
@@ -170,7 +73,7 @@ Mint_LockAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_UnlockAudio(_THIS)
|
||||
MINTDMA8_UnlockDevice(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
|
||||
@@ -181,57 +84,59 @@ Mint_UnlockAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CloseAudio(_THIS)
|
||||
MINTDMA8_CloseDevice(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
if (this->hidden != NULL) {
|
||||
/* Stop replay */
|
||||
void *oldpile = (void *) Super(0);
|
||||
|
||||
/* Stop replay */
|
||||
oldpile = (void *) Super(0);
|
||||
DMAAUDIO_IO.control = 0;
|
||||
Super(oldpile);
|
||||
DMAAUDIO_IO.control = 0;
|
||||
Super(oldpile);
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
|
||||
|
||||
/* Disable interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
/* Disable interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
|
||||
SDL_free(this->buffer);
|
||||
this->buffer = NULL;
|
||||
}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTDMA8_CheckAudio(_THIS)
|
||||
{
|
||||
int i, masterprediv, sfreq;
|
||||
unsigned long masterclock;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
if (spec->channels > 2) {
|
||||
spec->channels = 2; /* no more than stereo! */
|
||||
if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2; /* no more than stereo! */
|
||||
}
|
||||
|
||||
/* Check formats available */
|
||||
spec->format = AUDIO_S8;
|
||||
this->spec.format = AUDIO_S8;
|
||||
|
||||
/* Calculate and select the closest frequency */
|
||||
sfreq = 0;
|
||||
@@ -272,22 +177,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
#endif
|
||||
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
|
||||
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
|
||||
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTDMA8_InitAudio(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
unsigned long buffer;
|
||||
@@ -316,7 +221,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
DMAAUDIO_IO.end_low = buffer & 255;
|
||||
|
||||
mode = 3 - MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
|
||||
if (spec->channels == 1) {
|
||||
if (this->spec.channels == 1) {
|
||||
mode |= 1 << 7;
|
||||
}
|
||||
DMAAUDIO_IO.sound_ctrl = mode;
|
||||
@@ -339,29 +244,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTDMA8_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_MintAudio_device = this;
|
||||
|
||||
/* Check audio capabilities */
|
||||
if (Mint_CheckAudio(this, spec) == -1) {
|
||||
return -1;
|
||||
if (MINTDMA8_CheckAudio(this) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate memory for audio buffers in DMA-able RAM */
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
|
||||
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
|
||||
if (SDL_MintAudio_audiobuf[0] == NULL) {
|
||||
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
|
||||
return (-1);
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
|
||||
SDL_MintAudio_numbuf = 0;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
|
||||
SDL_MintAudio_audiosize = spec->size;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
|
||||
SDL_MintAudio_audiosize = this->spec.size;
|
||||
SDL_MintAudio_mutex = 0;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
|
||||
@@ -372,9 +288,56 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SDL_MintAudio_CheckFpu();
|
||||
|
||||
/* Setup audio hardware */
|
||||
Mint_InitAudio(this, spec);
|
||||
MINTDMA8_InitAudio(this);
|
||||
|
||||
return (1); /* We don't use threaded audio */
|
||||
return 1; /* good to go. */
|
||||
}
|
||||
|
||||
static int
|
||||
MINTDMA8_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Cookie _MCH present ? if not, assume ST machine */
|
||||
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
|
||||
cookie_mch = MCH_ST;
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 8 bits audio */
|
||||
if ((cookie_snd & SND_8BIT) == 0) {
|
||||
SDL_SetError(DEBUG_NAME "no 8 bits sound");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (cookie_snd & SND_16BIT) {
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError(DEBUG_NAME "audio locked by other application");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
}
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MINTDMA8_OpenDevice;
|
||||
impl->CloseDevice = MINTDMA8_CloseDevice;
|
||||
impl->LockAudio = MINTDMA8_LockAudio;
|
||||
impl->UnlockAudio = MINTDMA8_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->SkipMixerLock = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver", MINTDMA8_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -63,176 +63,83 @@ static unsigned long cookie_snd, cookie_gsxb;
|
||||
|
||||
/*--- Audio driver functions ---*/
|
||||
|
||||
static void Mint_CloseAudio(_THIS);
|
||||
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_LockAudio(_THIS);
|
||||
static void Mint_UnlockAudio(_THIS);
|
||||
|
||||
/* To check/init hardware audio */
|
||||
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
|
||||
|
||||
/* GSXB callbacks */
|
||||
static void Mint_GsxbInterrupt(void);
|
||||
static void Mint_GsxbNullInterrupt(void);
|
||||
|
||||
/*--- Audio driver bootstrap functions ---*/
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
|
||||
|
||||
/* Check if user asked a different audio driver */
|
||||
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 16 bits audio */
|
||||
if ((cookie_snd & SND_16BIT) == 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie GSXB present ? */
|
||||
cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
|
||||
|
||||
/* Is it GSXB ? */
|
||||
if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
|
||||
return (1);
|
||||
}
|
||||
static void MINTGSXB_GsxbInterrupt(void);
|
||||
static void MINTGSXB_GsxbNullInterrupt(void);
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Mint_OpenAudio;
|
||||
this->CloseAudio = Mint_CloseAudio;
|
||||
this->LockAudio = Mint_LockAudio;
|
||||
this->UnlockAudio = Mint_UnlockAudio;
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
static void
|
||||
Mint_LockAudio(_THIS)
|
||||
MINTGSXB_LockDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
Buffoper(0);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_UnlockAudio(_THIS)
|
||||
MINTGSXB_UnlockDevice(_THIS)
|
||||
{
|
||||
/* Restart replay */
|
||||
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CloseAudio(_THIS)
|
||||
MINTGSXB_CloseDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
Buffoper(0);
|
||||
if (this->hidden != NULL) {
|
||||
/* Stop replay */
|
||||
Buffoper(0);
|
||||
|
||||
/* Uninstall interrupt */
|
||||
if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
|
||||
/* Uninstall interrupt */
|
||||
if (NSetinterrupt(2, SI_NONE, MINTGSXB_GsxbNullInterrupt) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {
|
||||
}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTGSXB_CheckAudio(_THIS)
|
||||
{
|
||||
long snd_format;
|
||||
int i, resolution, format_signed, format_bigendian;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
int valid_datatype = 0;
|
||||
|
||||
resolution = SDL_AUDIO_BITSIZE(spec->format);
|
||||
format_signed = SDL_AUDIO_ISSIGNED(spec->format);
|
||||
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format);
|
||||
resolution = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
|
||||
format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", resolution));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", format_signed));
|
||||
DEBUG_PRINT(("big endian=%d, ", format_bigendian));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
if (spec->channels > 2) {
|
||||
spec->channels = 2; /* no more than stereo! */
|
||||
if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2; /* no more than stereo! */
|
||||
}
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
/* Check formats available */
|
||||
snd_format = Sndstatus(SND_QUERYFORMATS);
|
||||
spec->format = test_format;
|
||||
resolution = SDL_AUDIO_BITSIZE(spec->format);
|
||||
format_signed = SDL_AUDIO_ISSIGNED(spec->format);
|
||||
format_bigendian = SDL_AUDIO_ISBIGENDIAN(spec->format);
|
||||
this->spec.format = test_format;
|
||||
resolution = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
|
||||
format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S8:
|
||||
@@ -279,14 +186,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
/* Ok */
|
||||
} else if (snd_format & SND_FORMATUNSIGNED) {
|
||||
/* Give unsigned format */
|
||||
spec->format = spec->format & (~SDL_AUDIO_MASK_SIGNED);
|
||||
this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_SIGNED);
|
||||
}
|
||||
} else {
|
||||
if (snd_format & SND_FORMATUNSIGNED) {
|
||||
/* Ok */
|
||||
} else if (snd_format & SND_FORMATSIGNED) {
|
||||
/* Give signed format */
|
||||
spec->format |= SDL_AUDIO_MASK_SIGNED;
|
||||
this->spec.format |= SDL_AUDIO_MASK_SIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,14 +202,14 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
/* Ok */
|
||||
} else if (snd_format & SND_FORMATLITTLEENDIAN) {
|
||||
/* Give little endian format */
|
||||
spec->format = spec->format & (~SDL_AUDIO_MASK_ENDIAN);
|
||||
this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_ENDIAN);
|
||||
}
|
||||
} else {
|
||||
if (snd_format & SND_FORMATLITTLEENDIAN) {
|
||||
/* Ok */
|
||||
} else if (snd_format & SND_FORMATBIGENDIAN) {
|
||||
/* Give big endian format */
|
||||
spec->format |= SDL_AUDIO_MASK_ENDIAN;
|
||||
this->spec.format |= SDL_AUDIO_MASK_ENDIAN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,22 +231,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
#endif
|
||||
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
|
||||
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
|
||||
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTGSXB_InitAudio(_THIS)
|
||||
{
|
||||
int channels_mode, prediv;
|
||||
void *buffer;
|
||||
@@ -352,23 +259,23 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
Setmontracks(0);
|
||||
|
||||
/* Select replay format */
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
|
||||
case 8:
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
channels_mode = STEREO8;
|
||||
} else {
|
||||
channels_mode = MONO8;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
channels_mode = STEREO16;
|
||||
} else {
|
||||
channels_mode = MONO16;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
channels_mode = STEREO32;
|
||||
} else {
|
||||
channels_mode = MONO32;
|
||||
@@ -387,12 +294,12 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Set buffer */
|
||||
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
|
||||
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
|
||||
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
|
||||
}
|
||||
|
||||
/* Install interrupt */
|
||||
if (NSetinterrupt(2, SI_PLAY, Mint_GsxbInterrupt) < 0) {
|
||||
if (NSetinterrupt(2, SI_PLAY, MINTGSXB_GsxbInterrupt) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
|
||||
}
|
||||
|
||||
@@ -402,35 +309,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTGSXB_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
/* Lock sound system */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError("Mint_OpenAudio: Audio system already in use");
|
||||
return (-1);
|
||||
SDL_SetError("MINTGSXB_OpenDevice: Audio system already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_MintAudio_device = this;
|
||||
|
||||
/* Check audio capabilities */
|
||||
if (Mint_CheckAudio(this, spec) == -1) {
|
||||
return -1;
|
||||
if (MINTGSXB_CheckAudio(this) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate memory for audio buffers in DMA-able RAM */
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
|
||||
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
|
||||
if (SDL_MintAudio_audiobuf[0] == NULL) {
|
||||
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
|
||||
return (-1);
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
|
||||
SDL_MintAudio_numbuf = 0;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
|
||||
SDL_MintAudio_audiosize = spec->size;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
|
||||
SDL_MintAudio_audiosize = this->spec.size;
|
||||
SDL_MintAudio_mutex = 0;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
|
||||
@@ -441,13 +359,13 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SDL_MintAudio_CheckFpu();
|
||||
|
||||
/* Setup audio hardware */
|
||||
Mint_InitAudio(this, spec);
|
||||
MINTGSXB_InitAudio(this);
|
||||
|
||||
return (1); /* We don't use threaded audio */
|
||||
return 1; /* good to go. */
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_GsxbInterrupt(void)
|
||||
MINTGSXB_GsxbInterrupt(void)
|
||||
{
|
||||
Uint8 *newbuf;
|
||||
|
||||
@@ -465,8 +383,57 @@ Mint_GsxbInterrupt(void)
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_GsxbNullInterrupt(void)
|
||||
MINTGSXB_GsxbNullInterrupt(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
MINTGSXB_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 16 bits audio */
|
||||
if ((cookie_snd & SND_16BIT) == 0) {
|
||||
SDL_SetError(DEBUG_NAME "no 16-bit sound");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cookie GSXB present ? */
|
||||
cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
|
||||
|
||||
/* Is it GSXB ? */
|
||||
if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
|
||||
SDL_SetError(DEBUG_NAME "no GSXB audio");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError(DEBUG_NAME "audio locked by other application");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MINTGSXB_OpenDevice;
|
||||
impl->CloseDevice = MINTGSXB_CloseDevice;
|
||||
impl->LockAudio = MINTGSXB_LockAudio;
|
||||
impl->UnlockAudio = MINTGSXB_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->SkipMixerLock = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver", MINTGSXB_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -61,192 +61,82 @@
|
||||
|
||||
/*--- Static variables ---*/
|
||||
|
||||
static unsigned long cookie_snd, cookie_mch;
|
||||
static cookie_mcsn_t *cookie_mcsn;
|
||||
|
||||
/*--- Audio driver functions ---*/
|
||||
|
||||
static void Mint_CloseAudio(_THIS);
|
||||
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_LockAudio(_THIS);
|
||||
static void Mint_UnlockAudio(_THIS);
|
||||
|
||||
/* To check/init hardware audio */
|
||||
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
|
||||
|
||||
/*--- Audio driver bootstrap functions ---*/
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
unsigned long dummy;
|
||||
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
|
||||
|
||||
SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);
|
||||
|
||||
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
|
||||
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if user asked a different audio driver */
|
||||
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie _MCH present ? if not, assume ST machine */
|
||||
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
|
||||
cookie_mch = MCH_ST;
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 16 bits audio */
|
||||
if ((cookie_snd & SND_16BIT) == 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie MCSN present ? */
|
||||
if (Getcookie(C_McSn, (long *) &cookie_mcsn) != C_FOUND) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if interrupt at end of replay */
|
||||
if (cookie_mcsn->pint == 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
|
||||
return (1);
|
||||
}
|
||||
static unsigned long cookie_snd = 0;
|
||||
static unsigned long cookie_mch = 0;
|
||||
static cookie_mcsn_t *cookie_mcsn = NULL;
|
||||
|
||||
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
|
||||
Mint_LockAudio(_THIS)
|
||||
MINTMCSN_LockDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
Buffoper(0);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_UnlockAudio(_THIS)
|
||||
MINTMCSN_UnlockDevice(_THIS)
|
||||
{
|
||||
/* Restart replay */
|
||||
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CloseAudio(_THIS)
|
||||
MINTMCSN_CloseDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
SDL_MintAudio_WaitThread();
|
||||
Buffoper(0);
|
||||
if (this->hidden != NULL) {
|
||||
/* Stop replay */
|
||||
SDL_MintAudio_WaitThread();
|
||||
Buffoper(0);
|
||||
|
||||
if (!SDL_MintAudio_mint_present) {
|
||||
/* Uninstall interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
if (!SDL_MintAudio_mint_present) {
|
||||
/* Uninstall interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {
|
||||
}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTMCSN_CheckAudio(_THIS)
|
||||
{
|
||||
int i;
|
||||
unsigned long masterclock, masterprediv;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
if (spec->channels > 2) {
|
||||
spec->channels = 2; /* no more than stereo! */
|
||||
if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2; /* no more than stereo! */
|
||||
}
|
||||
|
||||
/* Check formats available */
|
||||
MINTAUDIO_freqcount = 0;
|
||||
switch (cookie_mcsn->play) {
|
||||
case MCSN_ST:
|
||||
spec->channels = 1;
|
||||
spec->format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */
|
||||
this->spec.channels = 1;
|
||||
this->spec.format = AUDIO_S8; /* FIXME: is it signed or unsigned ? */
|
||||
SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1);
|
||||
break;
|
||||
case MCSN_TT: /* Also STE, Mega STE */
|
||||
spec->format = AUDIO_S8;
|
||||
this->spec.format = AUDIO_S8;
|
||||
masterclock = MASTERCLOCK_STE;
|
||||
masterprediv = MASTERPREDIV_STE;
|
||||
if ((cookie_mch >> 16) == MCH_TT) {
|
||||
@@ -280,10 +170,10 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
(1 << i) - 1, -1);
|
||||
}
|
||||
}
|
||||
spec->format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
|
||||
if ((SDL_AUDIO_BITSIZE(spec->format)) == 16) {
|
||||
spec->format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */
|
||||
spec->channels = 2; /* 16 bits always stereo */
|
||||
this->spec.format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
|
||||
if ((SDL_AUDIO_BITSIZE(this->spec.format)) == 16) {
|
||||
this->spec.format |= SDL_AUDIO_MASK_ENDIAN; /* Audio is always big endian */
|
||||
this->spec.channels = 2; /* 16 bits always stereo */
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -297,22 +187,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
#endif
|
||||
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
|
||||
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
|
||||
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTMCSN_InitAudio(_THIS)
|
||||
{
|
||||
int channels_mode, prediv, dmaclock;
|
||||
void *buffer;
|
||||
@@ -329,9 +219,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Select replay format */
|
||||
channels_mode = STEREO16;
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
|
||||
case 8:
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
channels_mode = STEREO8;
|
||||
} else {
|
||||
channels_mode = MONO8;
|
||||
@@ -358,7 +248,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Set buffer */
|
||||
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
|
||||
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
|
||||
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
|
||||
}
|
||||
|
||||
@@ -381,35 +271,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTMCSN_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
/* Lock sound system */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError("Mint_OpenAudio: Audio system already in use");
|
||||
return (-1);
|
||||
SDL_SetError("MINTMCSN_OpenDevice: Audio system already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_MintAudio_device = this;
|
||||
|
||||
/* Check audio capabilities */
|
||||
if (Mint_CheckAudio(this, spec) == -1) {
|
||||
return -1;
|
||||
if (MINTMCSN_CheckAudio(this) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate memory for audio buffers in DMA-able RAM */
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
|
||||
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
|
||||
if (SDL_MintAudio_audiobuf[0] == NULL) {
|
||||
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
|
||||
return (-1);
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
|
||||
SDL_MintAudio_numbuf = 0;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
|
||||
SDL_MintAudio_audiosize = spec->size;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
|
||||
SDL_MintAudio_audiosize = this->spec.size;
|
||||
SDL_MintAudio_mutex = 0;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
|
||||
@@ -420,9 +321,75 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SDL_MintAudio_CheckFpu();
|
||||
|
||||
/* Setup audio hardware */
|
||||
Mint_InitAudio(this, spec);
|
||||
MINTMCSN_InitAudio(this);
|
||||
|
||||
return (1); /* We don't use SDL threaded audio */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Check if interrupt at end of replay */
|
||||
if (cookie_mcsn->pint == 0) {
|
||||
SDL_SetError(DEBUG_NAME "no interrupt at end of replay");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError(DEBUG_NAME "audio locked by other application");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MINTMCSN_OpenDevice;
|
||||
impl->CloseDevice = MINTMCSN_CloseDevice;
|
||||
impl->LockAudio = MINTMCSN_LockAudio;
|
||||
impl->UnlockAudio = MINTMCSN_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->SkipMixerLock = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver", MINTMCSN_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -59,8 +59,9 @@
|
||||
|
||||
/*--- Static variables ---*/
|
||||
|
||||
static unsigned long cookie_snd, cookie_mch;
|
||||
static cookie_stfa_t *cookie_stfa;
|
||||
static unsigned long cookie_snd = 0;
|
||||
static unsigned long cookie_mch = 0;
|
||||
static cookie_stfa_t *cookie_stfa = NULL;
|
||||
|
||||
static const int freqs[16] = {
|
||||
4995, 6269, 7493, 8192,
|
||||
@@ -69,157 +70,66 @@ static const int freqs[16] = {
|
||||
30720, 32336, 43885, 49152
|
||||
};
|
||||
|
||||
/*--- Audio driver functions ---*/
|
||||
|
||||
static void Mint_CloseAudio(_THIS);
|
||||
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_LockAudio(_THIS);
|
||||
static void Mint_UnlockAudio(_THIS);
|
||||
|
||||
/* To check/init hardware audio */
|
||||
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
|
||||
|
||||
/*--- Audio driver bootstrap functions ---*/
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
|
||||
|
||||
/* Check if user asked a different audio driver */
|
||||
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie _MCH present ? if not, assume ST machine */
|
||||
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
|
||||
cookie_mch = MCH_ST;
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Cookie STFA present ? */
|
||||
if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no STFA audio\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
SDL_MintAudio_stfa = cookie_stfa;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
MINTSTFA_LockDevice(_THIS)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Mint_OpenAudio;
|
||||
this->CloseAudio = Mint_CloseAudio;
|
||||
this->LockAudio = Mint_LockAudio;
|
||||
this->UnlockAudio = Mint_UnlockAudio;
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_STFA_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
static void
|
||||
Mint_LockAudio(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
|
||||
/* Stop replay */
|
||||
oldpile = (void *) Super(0);
|
||||
void *oldpile = (void *) Super(0);
|
||||
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
|
||||
Super(oldpile);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_UnlockAudio(_THIS)
|
||||
MINTSTFA_UnlockDevice(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
|
||||
/* Restart replay */
|
||||
oldpile = (void *) Super(0);
|
||||
void *oldpile = (void *) Super(0);
|
||||
cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT;
|
||||
Super(oldpile);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CloseAudio(_THIS)
|
||||
MINTSTFA_CloseDevice(_THIS)
|
||||
{
|
||||
void *oldpile;
|
||||
if (this->hidden != NULL) {
|
||||
/* Stop replay */
|
||||
void *oldpile = (void *) Super(0);
|
||||
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
|
||||
Super(oldpile);
|
||||
|
||||
/* Stop replay */
|
||||
oldpile = (void *) Super(0);
|
||||
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
|
||||
Super(oldpile);
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {
|
||||
}
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTSTFA_CheckAudio(_THIS)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
if (SDL_AUDIO_BITSIZE(spec->format) > 16) {
|
||||
spec->format = AUDIO_S16SYS; /* clamp out int32/float32 ... */
|
||||
if (SDL_AUDIO_BITSIZE(this->spec.format) > 16) {
|
||||
this->spec.format = AUDIO_S16SYS; /* clamp out int32/float32 ... */
|
||||
}
|
||||
|
||||
if (spec->channels > 2) {
|
||||
spec->channels = 2; /* no more than stereo! */
|
||||
if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2; /* no more than stereo! */
|
||||
}
|
||||
|
||||
/* Check formats available */
|
||||
@@ -237,29 +147,25 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
#endif
|
||||
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
|
||||
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
|
||||
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTSTFA_InitAudio(_THIS)
|
||||
{
|
||||
void *buffer;
|
||||
void *oldpile;
|
||||
|
||||
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
|
||||
|
||||
oldpile = (void *) Super(0);
|
||||
void *buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
|
||||
void *oldpile = (void *) Super(0);
|
||||
|
||||
/* Stop replay */
|
||||
cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
|
||||
@@ -267,22 +173,22 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
/* Select replay format */
|
||||
cookie_stfa->sound_control =
|
||||
MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
|
||||
if (SDL_AUDIO_BITSIZE(spec->format) == 8) {
|
||||
if (SDL_AUDIO_BITSIZE(this->spec.format) == 8) {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
|
||||
} else {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
|
||||
}
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
|
||||
} else {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_MONO;
|
||||
}
|
||||
if (SDL_AUDIO_ISSIGNED(spec->format) != 0) {
|
||||
if (SDL_AUDIO_ISSIGNED(this->spec.format) != 0) {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
|
||||
} else {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
|
||||
}
|
||||
if (SDL_AUDIO_ISBIGENDIAN(spec->format) != 0) {
|
||||
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format) != 0) {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
|
||||
} else {
|
||||
cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
|
||||
@@ -290,7 +196,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Set buffer */
|
||||
cookie_stfa->sound_start = (unsigned long) buffer;
|
||||
cookie_stfa->sound_end = (unsigned long) (buffer + spec->size);
|
||||
cookie_stfa->sound_end = (unsigned long) (buffer + this->spec.size);
|
||||
|
||||
/* Set interrupt */
|
||||
cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
|
||||
@@ -304,29 +210,40 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTSTFA_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_MintAudio_device = this;
|
||||
|
||||
/* Check audio capabilities */
|
||||
if (Mint_CheckAudio(this, spec) == -1) {
|
||||
return -1;
|
||||
if (MINTSTFA_CheckAudio(this) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate memory for audio buffers in DMA-able RAM */
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
|
||||
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
|
||||
if (SDL_MintAudio_audiobuf[0] == NULL) {
|
||||
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
|
||||
return (-1);
|
||||
SDL_OutOfMemory()
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
return 0;
|
||||
}
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
|
||||
SDL_MintAudio_numbuf = 0;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
|
||||
SDL_MintAudio_audiosize = spec->size;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
|
||||
SDL_MintAudio_audiosize = this->spec.size;
|
||||
SDL_MintAudio_mutex = 0;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
|
||||
@@ -337,9 +254,49 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SDL_MintAudio_CheckFpu();
|
||||
|
||||
/* Setup audio hardware */
|
||||
Mint_InitAudio(this, spec);
|
||||
MINTSTFA_InitAudio(this);
|
||||
|
||||
return (1); /* We don't use threaded audio */
|
||||
return 1; /* good to go. */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MINTSTFA_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Cookie _MCH present ? if not, assume ST machine */
|
||||
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
|
||||
cookie_mch = MCH_ST;
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Cookie STFA present ? */
|
||||
if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
|
||||
SDL_SetError(DEBUG_NAME "no STFA audio");
|
||||
return (0);
|
||||
}
|
||||
|
||||
SDL_MintAudio_stfa = cookie_stfa;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MINTSTFA_OpenDevice;
|
||||
impl->CloseDevice = MINTSTFA_CloseDevice;
|
||||
impl->LockAudio = MINTSTFA_LockAudio;
|
||||
impl->UnlockAudio = MINTSTFA_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->SkipMixerLock = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_STFA_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver", MINTSTFA_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -60,147 +60,50 @@
|
||||
#define DEBUG_PRINT(what)
|
||||
#endif
|
||||
|
||||
/*--- Static variables ---*/
|
||||
|
||||
static unsigned long cookie_snd;
|
||||
|
||||
/*--- Audio driver functions ---*/
|
||||
|
||||
static void Mint_CloseAudio(_THIS);
|
||||
static int Mint_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_LockAudio(_THIS);
|
||||
static void Mint_UnlockAudio(_THIS);
|
||||
|
||||
/* To check/init hardware audio */
|
||||
static int Mint_CheckAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Mint_InitAudio(_THIS, SDL_AudioSpec * spec);
|
||||
|
||||
/*--- Audio driver bootstrap functions ---*/
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
unsigned long dummy;
|
||||
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
|
||||
|
||||
/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND); */
|
||||
SDL_MintAudio_mint_present = SDL_FALSE;
|
||||
|
||||
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
|
||||
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if user asked a different audio driver */
|
||||
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
|
||||
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 16 bits audio */
|
||||
if ((cookie_snd & SND_16BIT) == 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
|
||||
return (1);
|
||||
}
|
||||
static unsigned long cookie_snd = 0;
|
||||
|
||||
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
|
||||
Mint_LockAudio(_THIS)
|
||||
MINTXBIOS_LockDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
Buffoper(0);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_UnlockAudio(_THIS)
|
||||
MINTXBIOS_UnlockDevice(_THIS)
|
||||
{
|
||||
/* Restart replay */
|
||||
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CloseAudio(_THIS)
|
||||
MINTXBIOS_CloseDevice(_THIS)
|
||||
{
|
||||
/* Stop replay */
|
||||
SDL_MintAudio_WaitThread();
|
||||
Buffoper(0);
|
||||
if (this->hidden != NULL) {
|
||||
/* Stop replay */
|
||||
SDL_MintAudio_WaitThread();
|
||||
Buffoper(0);
|
||||
|
||||
if (!SDL_MintAudio_mint_present) {
|
||||
/* Uninstall interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
if (!SDL_MintAudio_mint_present) {
|
||||
/* Uninstall interrupt */
|
||||
Jdisint(MFP_DMASOUND);
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
|
||||
/* Wait if currently playing sound */
|
||||
while (SDL_MintAudio_mutex != 0) {
|
||||
}
|
||||
|
||||
/* Clear buffers */
|
||||
if (SDL_MintAudio_audiobuf[0]) {
|
||||
Mfree(SDL_MintAudio_audiobuf[0]);
|
||||
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
|
||||
}
|
||||
|
||||
/* Unlock sound system */
|
||||
Unlocksnd();
|
||||
}
|
||||
|
||||
/* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
|
||||
@@ -269,7 +172,7 @@ Devconnect2(int src, int dst, int sclk, int pre)
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_CheckExternalClock(_THIS)
|
||||
MINTXBIOS_CheckExternalClock(_THIS)
|
||||
{
|
||||
#define SIZE_BUF_CLOCK_MEASURE (44100/10)
|
||||
|
||||
@@ -355,33 +258,33 @@ Mint_CheckExternalClock(_THIS)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTXBIOS_CheckAudio(_THIS)
|
||||
{
|
||||
int i;
|
||||
Uint32 extclock;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
spec->format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
|
||||
this->spec.format |= SDL_AUDIO_MASK_SIGNED; /* Audio is always signed */
|
||||
|
||||
/* clamp out int32/float32 */
|
||||
if (SDL_AUDIO_BITSIZE(spec->format) >= 16) {
|
||||
spec->format = AUDIO_S16MSB; /* Audio is always big endian */
|
||||
spec->channels = 2; /* 16 bits always stereo */
|
||||
} else if (spec->channels > 2) {
|
||||
spec->channels = 2; /* no more than stereo! */
|
||||
if (SDL_AUDIO_BITSIZE(this->spec.format) >= 16) {
|
||||
this->spec.format = AUDIO_S16MSB; /* Audio is always big endian */
|
||||
this->spec.channels = 2; /* 16 bits always stereo */
|
||||
} else if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2; /* no more than stereo! */
|
||||
}
|
||||
|
||||
MINTAUDIO_freqcount = 0;
|
||||
|
||||
/* Add external clocks if present */
|
||||
Mint_CheckExternalClock(this);
|
||||
MINTXBIOS_CheckExternalClock(this);
|
||||
|
||||
/* Standard clocks */
|
||||
for (i = 1; i < 12; i++) {
|
||||
@@ -404,22 +307,22 @@ Mint_CheckAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
#endif
|
||||
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, spec->freq);
|
||||
spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
|
||||
this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
|
||||
SDL_AUDIO_BITSIZE(spec->format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(spec->format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(spec->format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(spec->format)));
|
||||
DEBUG_PRINT(("channels=%d, ", spec->channels));
|
||||
DEBUG_PRINT(("freq=%d\n", spec->freq));
|
||||
SDL_AUDIO_BITSIZE(this->spec.format)));
|
||||
DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
|
||||
DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
|
||||
DEBUG_PRINT(("big endian=%d, ", SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
|
||||
DEBUG_PRINT(("channels=%d, ", this->spec.channels));
|
||||
DEBUG_PRINT(("freq=%d\n", this->spec.freq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTXBIOS_InitAudio(_THIS)
|
||||
{
|
||||
int channels_mode, dmaclock, prediv;
|
||||
void *buffer;
|
||||
@@ -436,9 +339,9 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Select replay format */
|
||||
channels_mode = STEREO16;
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
|
||||
case 8:
|
||||
if (spec->channels == 2) {
|
||||
if (this->spec.channels == 2) {
|
||||
channels_mode = STEREO8;
|
||||
} else {
|
||||
channels_mode = MONO8;
|
||||
@@ -461,7 +364,7 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* Set buffer */
|
||||
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
|
||||
if (Setbuffer(0, buffer, buffer + spec->size) < 0) {
|
||||
if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
|
||||
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
|
||||
}
|
||||
|
||||
@@ -485,35 +388,46 @@ Mint_InitAudio(_THIS, SDL_AudioSpec * spec)
|
||||
}
|
||||
|
||||
static int
|
||||
Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MINTXBIOS_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
/* Lock sound system */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError("Mint_OpenAudio: Audio system already in use");
|
||||
return (-1);
|
||||
SDL_SetError("MINTXBIOS_OpenAudio: Audio system already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_MintAudio_device = this;
|
||||
|
||||
/* Check audio capabilities */
|
||||
if (Mint_CheckAudio(this, spec) == -1) {
|
||||
return -1;
|
||||
if (MINTXBIOS_CheckAudio(this) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate memory for audio buffers in DMA-able RAM */
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
|
||||
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size * 2, MX_STRAM);
|
||||
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
|
||||
if (SDL_MintAudio_audiobuf[0] == NULL) {
|
||||
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
|
||||
return (-1);
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
|
||||
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
|
||||
SDL_MintAudio_numbuf = 0;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
|
||||
SDL_MintAudio_audiosize = spec->size;
|
||||
SDL_memset(SDL_MintAudio_audiobuf[0],this->spec.silence,this->spec.size*2);
|
||||
SDL_MintAudio_audiosize = this->spec.size;
|
||||
SDL_MintAudio_mutex = 0;
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
|
||||
@@ -524,9 +438,58 @@ Mint_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
SDL_MintAudio_CheckFpu();
|
||||
|
||||
/* Setup audio hardware */
|
||||
Mint_InitAudio(this, spec);
|
||||
MINTXBIOS_InitAudio(this);
|
||||
|
||||
return (1); /* We don't use SDL threaded audio */
|
||||
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;
|
||||
|
||||
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
|
||||
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Cookie _SND present ? if not, assume ST machine */
|
||||
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
|
||||
cookie_snd = SND_PSG;
|
||||
}
|
||||
|
||||
/* Check if we have 16 bits audio */
|
||||
if ((cookie_snd & SND_16BIT) == 0) {
|
||||
SDL_SetError(DEBUG_NAME "no 16-bit sound");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if audio is lockable */
|
||||
if (Locksnd() != 1) {
|
||||
SDL_SetError(DEBUG_NAME "audio locked by other application");
|
||||
return (0);
|
||||
}
|
||||
|
||||
Unlocksnd();
|
||||
|
||||
DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MINTXBIOS_OpenDevice;
|
||||
impl->CloseDevice = MINTXBIOS_CloseDevice;
|
||||
impl->LockAudio = MINTXBIOS_LockAudio;
|
||||
impl->UnlockAudio = MINTXBIOS_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
impl->SkipMixerLock = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
|
||||
MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver", MINTXBIOS_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -31,70 +31,6 @@
|
||||
|
||||
static BOOL inUse[NUM_BUFFERS];
|
||||
|
||||
/* Audio driver functions */
|
||||
static int MME_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void MME_WaitAudio(_THIS);
|
||||
static Uint8 *MME_GetAudioBuf(_THIS);
|
||||
static void MME_PlayAudio(_THIS);
|
||||
static void MME_WaitDone(_THIS);
|
||||
static void MME_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
if (device) {
|
||||
if (device->hidden) {
|
||||
SDL_free(device->hidden);
|
||||
device->hidden = NULL;
|
||||
}
|
||||
SDL_free(device);
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = MME_OpenAudio;
|
||||
this->WaitAudio = MME_WaitAudio;
|
||||
this->PlayAudio = MME_PlayAudio;
|
||||
this->GetAudioBuf = MME_GetAudioBuf;
|
||||
this->WaitDone = MME_WaitDone;
|
||||
this->CloseAudio = MME_CloseAudio;
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap MMEAUDIO_bootstrap = {
|
||||
"waveout", "Tru64 MME WaveOut",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
static void
|
||||
SetMMerror(char *function, MMRESULT code)
|
||||
{
|
||||
@@ -108,7 +44,7 @@ SetMMerror(char *function, MMRESULT code)
|
||||
}
|
||||
|
||||
static void CALLBACK
|
||||
MME_CALLBACK(HWAVEOUT hwo,
|
||||
MME_Callback(HWAVEOUT hwo,
|
||||
UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2)
|
||||
{
|
||||
WAVEHDR *wp = (WAVEHDR *) dwParam1;
|
||||
@@ -118,116 +54,137 @@ MME_CALLBACK(HWAVEOUT hwo,
|
||||
}
|
||||
|
||||
static int
|
||||
MME_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
MME_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
int valid_format = 0;
|
||||
MMRESULT result;
|
||||
Uint8 *mixbuf = NULL;
|
||||
int i;
|
||||
|
||||
mixbuf = NULL;
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set basic WAVE format parameters */
|
||||
shm = mmeAllocMem(sizeof(*shm));
|
||||
if (shm == NULL) {
|
||||
SDL_SetError("Out of memory: shm");
|
||||
return (-1);
|
||||
this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
|
||||
if (this->hidden->shm == NULL) {
|
||||
MME_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
shm->sound = 0;
|
||||
shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
|
||||
SDL_memset(this->hidden->shm, '\0', sizeof (*this->hidden->shm));
|
||||
this->hidden->shm->sound = 0;
|
||||
this->hidden->shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
|
||||
/* Determine the audio parameters from the AudioSpec */
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
case 8:
|
||||
/* Unsigned 8 bit audio data */
|
||||
spec->format = AUDIO_U8;
|
||||
shm->wFmt.wBitsPerSample = 8;
|
||||
break;
|
||||
case 16:
|
||||
/* Signed 16 bit audio data */
|
||||
spec->format = AUDIO_S16;
|
||||
shm->wFmt.wBitsPerSample = 16;
|
||||
break;
|
||||
case 32:
|
||||
/* Signed 32 bit audio data */
|
||||
spec->format = AUDIO_S32;
|
||||
shm->wFmt.wBitsPerSample = 32;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
/* Try for a closest match on audio format */
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!valid_format && test_format;) {
|
||||
valid_format = 1;
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S16:
|
||||
case AUDIO_S32:
|
||||
break;
|
||||
default:
|
||||
valid_format = 0;
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
MME_CloseDevice(this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->spec.format = test_format;
|
||||
this->hidden->shm->wFmt.wBitsPerSample = SDL_AUDIO_BITSIZE(test_format);
|
||||
|
||||
/* !!! FIXME: Can this handle more than stereo? */
|
||||
shm->wFmt.wf.nChannels = spec->channels;
|
||||
shm->wFmt.wf.nSamplesPerSec = spec->freq;
|
||||
shm->wFmt.wf.nBlockAlign =
|
||||
shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
|
||||
shm->wFmt.wf.nAvgBytesPerSec =
|
||||
shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
|
||||
this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
|
||||
this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
|
||||
this->hidden->shm->wFmt.wf.nBlockAlign =
|
||||
this->hidden->shm->wFmt.wf.nChannels *
|
||||
this->hidden->shm->wFmt.wBitsPerSample / 8;
|
||||
this->hidden->shm->wFmt.wf.nAvgBytesPerSec =
|
||||
this->hidden->shm->wFmt.wf.nSamplesPerSec *
|
||||
this->hidden->shm->wFmt.wf.nBlockAlign;
|
||||
|
||||
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
|
||||
if (spec->samples < (spec->freq / 4))
|
||||
spec->samples = ((spec->freq / 4) + 3) & ~3;
|
||||
if (this->spec.samples < (this->spec.freq / 4))
|
||||
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Open the audio device */
|
||||
result = waveOutOpen(&(shm->sound),
|
||||
result = waveOutOpen(&(this->hidden->shm->sound),
|
||||
WAVE_MAPPER,
|
||||
&(shm->wFmt.wf),
|
||||
MME_CALLBACK,
|
||||
&(this->hidden->shm->wFmt.wf),
|
||||
MME_Callback,
|
||||
NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
MME_CloseDevice(this);
|
||||
SetMMerror("waveOutOpen()", result);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the sound buffers */
|
||||
mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (spec->size));
|
||||
mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
|
||||
if (mixbuf == NULL) {
|
||||
SDL_SetError("Out of memory: mixbuf");
|
||||
return (-1);
|
||||
MME_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
this->hidden->mixbuf = mixbuf;
|
||||
|
||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||
shm->wHdr[i].lpData = &mixbuf[i * (spec->size)];
|
||||
shm->wHdr[i].dwBufferLength = spec->size;
|
||||
shm->wHdr[i].dwFlags = 0;
|
||||
shm->wHdr[i].dwUser = i;
|
||||
shm->wHdr[i].dwLoops = 0; /* loop control counter */
|
||||
shm->wHdr[i].lpNext = NULL; /* reserved for driver */
|
||||
shm->wHdr[i].reserved = 0;
|
||||
this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
|
||||
this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
|
||||
this->hidden->shm->wHdr[i].dwFlags = 0;
|
||||
this->hidden->shm->wHdr[i].dwUser = i;
|
||||
this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
|
||||
this->hidden->shm->wHdr[i].lpNext = NULL; /* reserved for driver */
|
||||
this->hidden->shm->wHdr[i].reserved = 0;
|
||||
inUse[i] = FALSE;
|
||||
}
|
||||
next_buffer = 0;
|
||||
return 0;
|
||||
this->hidden->next_buffer = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MME_WaitAudio(_THIS)
|
||||
MME_WaitDevice(_THIS)
|
||||
{
|
||||
while (inUse[next_buffer]) {
|
||||
while (inUse[this->hidden->next_buffer]) {
|
||||
mmeWaitForCallbacks();
|
||||
mmeProcessCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
MME_GetAudioBuf(_THIS)
|
||||
MME_GetDeviceBuf(_THIS)
|
||||
{
|
||||
Uint8 *retval;
|
||||
|
||||
inUse[next_buffer] = TRUE;
|
||||
retval = (Uint8 *) (shm->wHdr[next_buffer].lpData);
|
||||
return retval;
|
||||
void *retval = this->hidden->shm->wHdr[this->hidden->next_buffer].lpData;
|
||||
inUse[this->hidden->next_buffer] = TRUE;
|
||||
return (Uint8 *) retval;
|
||||
}
|
||||
|
||||
static void
|
||||
MME_PlayAudio(_THIS)
|
||||
MME_PlayDevice(_THIS)
|
||||
{
|
||||
/* Queue it up */
|
||||
waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
|
||||
next_buffer = (next_buffer + 1) % NUM_BUFFERS;
|
||||
waveOutWrite(this->hidden->shm->sound,
|
||||
&(this->hidden->shm->wHdr[this->hidden->next_buffer]),
|
||||
sizeof (WAVEHDR));
|
||||
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -236,13 +193,13 @@ MME_WaitDone(_THIS)
|
||||
MMRESULT result;
|
||||
int i;
|
||||
|
||||
if (shm->sound) {
|
||||
if (this->hidden->shm->sound) {
|
||||
for (i = 0; i < NUM_BUFFERS; i++)
|
||||
while (inUse[i]) {
|
||||
mmeWaitForCallbacks();
|
||||
mmeProcessCallbacks();
|
||||
}
|
||||
result = waveOutReset(shm->sound);
|
||||
result = waveOutReset(this->hidden->shm->sound);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("waveOutReset()", result);
|
||||
mmeProcessCallbacks();
|
||||
@@ -250,29 +207,54 @@ MME_WaitDone(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
MME_CloseAudio(_THIS)
|
||||
MME_CloseDevice(_THIS)
|
||||
{
|
||||
MMRESULT result;
|
||||
if (this->hidden != NULL) {
|
||||
MMRESULT result;
|
||||
|
||||
if (mixbuf) {
|
||||
result = mmeFreeBuffer(mixbuf);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("mmeFreeBuffer", result);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
|
||||
if (shm) {
|
||||
if (shm->sound) {
|
||||
result = waveOutClose(shm->sound);
|
||||
if (this->hidden->mixbuf) {
|
||||
result = mmeFreeBuffer(this->hidden->mixbuf);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("waveOutClose()", result);
|
||||
mmeProcessCallbacks();
|
||||
SetMMerror("mmeFreeBuffer", result);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
result = mmeFreeMem(shm);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("mmeFreeMem()", result);
|
||||
shm = NULL;
|
||||
|
||||
if (this->hidden->shm) {
|
||||
if (this->hidden->shm->sound) {
|
||||
result = waveOutClose(this->hidden->shm->sound);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("waveOutClose()", result);
|
||||
mmeProcessCallbacks();
|
||||
}
|
||||
result = mmeFreeMem(this->hidden->shm);
|
||||
if (result != MMSYSERR_NOERROR)
|
||||
SetMMerror("mmeFreeMem()", result);
|
||||
this->hidden->shm = NULL;
|
||||
}
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
MME_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = MME_OpenDevice;
|
||||
impl->WaitDevice = MME_WaitDevice;
|
||||
impl->WaitDone = MME_WaitDone;
|
||||
impl->PlayDevice = MME_PlayDevice;
|
||||
impl->GetDeviceBuf = MME_GetDeviceBuf;
|
||||
impl->CloseDevice = MME_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* !!! FIXME: Windows "windib" driver is called waveout, too */
|
||||
AudioBootStrap MMEAUDIO_bootstrap = {
|
||||
"waveout", "Tru64 MME WaveOut", MME_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
/* Allow access to a raw mixing buffer */
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_mmeaudio_h
|
||||
#define _SDL_mmeaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
#define NUM_BUFFERS 2
|
||||
|
||||
@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
|
||||
int next_buffer;
|
||||
};
|
||||
|
||||
#define shm (this->hidden->shm)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define next_buffer (this->hidden->next_buffer)
|
||||
/* Old variable names */
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
#endif /* _SDL_mmeaudio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -32,106 +32,149 @@
|
||||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_nasaudio.h"
|
||||
|
||||
/* The tag name used by artsc audio */
|
||||
/* The tag name used by nas audio */
|
||||
#define NAS_DRIVER_NAME "nas"
|
||||
|
||||
static struct SDL_PrivateAudioData *this2 = NULL;
|
||||
|
||||
/* Audio driver functions */
|
||||
static int NAS_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void NAS_WaitAudio(_THIS);
|
||||
static void NAS_PlayAudio(_THIS);
|
||||
static Uint8 *NAS_GetAudioBuf(_THIS);
|
||||
static void NAS_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
static void (*NAS_AuCloseServer)(AuServer *);
|
||||
static void (*NAS_AuNextEvent)(AuServer *, AuBool, AuEvent *);
|
||||
static AuBool (*NAS_AuDispatchEvent)(AuServer *, AuEvent *);
|
||||
static AuFlowID (*NAS_AuCreateFlow)(AuServer *, AuStatus *);
|
||||
static void (*NAS_AuStartFlow)(AuServer *, AuFlowID, AuStatus *);
|
||||
static void (*NAS_AuSetElements)
|
||||
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
|
||||
static void (*NAS_AuWriteElement)
|
||||
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
|
||||
static AuServer *(*NAS_AuOpenServer)
|
||||
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
|
||||
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
|
||||
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
|
||||
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
|
||||
|
||||
static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
|
||||
static void *nas_handle = NULL;
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
load_nas_sym(const char *fn, void **addr)
|
||||
{
|
||||
AuServer *aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
||||
if (!aud)
|
||||
*addr = SDL_LoadFunction(nas_handle, fn);
|
||||
if (*addr == NULL) {
|
||||
return 0;
|
||||
|
||||
AuCloseServer(aud);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
|
||||
#define SDL_NAS_SYM(x) \
|
||||
if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
|
||||
#else
|
||||
#define SDL_NAS_SYM(x) NAS_##x = x
|
||||
#endif
|
||||
|
||||
static int load_nas_syms(void)
|
||||
{
|
||||
SDL_NAS_SYM(AuCloseServer);
|
||||
SDL_NAS_SYM(AuNextEvent);
|
||||
SDL_NAS_SYM(AuDispatchEvent);
|
||||
SDL_NAS_SYM(AuCreateFlow);
|
||||
SDL_NAS_SYM(AuStartFlow);
|
||||
SDL_NAS_SYM(AuSetElements);
|
||||
SDL_NAS_SYM(AuWriteElement);
|
||||
SDL_NAS_SYM(AuOpenServer);
|
||||
SDL_NAS_SYM(AuRegisterEventHandler);
|
||||
return 0;
|
||||
}
|
||||
#undef SDL_NAS_SYM
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
UnloadNASLibrary(void)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
if (nas_handle != NULL) {
|
||||
SDL_UnloadObject(nas_handle);
|
||||
nas_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
static int
|
||||
LoadNASLibrary(void)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
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));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = NAS_OpenAudio;
|
||||
this->WaitAudio = NAS_WaitAudio;
|
||||
this->PlayAudio = NAS_PlayAudio;
|
||||
this->GetAudioBuf = NAS_GetAudioBuf;
|
||||
this->CloseAudio = NAS_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
return retval;
|
||||
}
|
||||
|
||||
AudioBootStrap NAS_bootstrap = {
|
||||
NAS_DRIVER_NAME, "Network Audio System",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
#else
|
||||
|
||||
static void
|
||||
UnloadNASLibrary(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
LoadNASLibrary(void)
|
||||
{
|
||||
load_nas_syms();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
NAS_WaitAudio(_THIS)
|
||||
NAS_WaitDevice(_THIS)
|
||||
{
|
||||
while (this->hidden->buf_free < this->hidden->mixlen) {
|
||||
AuEvent ev;
|
||||
AuNextEvent(this->hidden->aud, AuTrue, &ev);
|
||||
AuDispatchEvent(this->hidden->aud, &ev);
|
||||
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
|
||||
NAS_AuDispatchEvent(this->hidden->aud, &ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
NAS_PlayAudio(_THIS)
|
||||
NAS_PlayDevice(_THIS)
|
||||
{
|
||||
while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
|
||||
in the hope that some of them is LowWater events telling us more
|
||||
of the buffer is free now than what we think. */
|
||||
while (this->hidden->mixlen > this->hidden->buf_free) {
|
||||
/*
|
||||
* We think the buffer is full? Yikes! Ask the server for events,
|
||||
* in the hope that some of them is LowWater events telling us more
|
||||
* of the buffer is free now than what we think.
|
||||
*/
|
||||
AuEvent ev;
|
||||
AuNextEvent(this->hidden->aud, AuTrue, &ev);
|
||||
AuDispatchEvent(this->hidden->aud, &ev);
|
||||
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
|
||||
NAS_AuDispatchEvent(this->hidden->aud, &ev);
|
||||
}
|
||||
this->hidden->buf_free -= this->hidden->mixlen;
|
||||
|
||||
/* Write the audio data */
|
||||
AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
|
||||
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
|
||||
this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
|
||||
|
||||
this->hidden->written += this->hidden->mixlen;
|
||||
@@ -142,21 +185,25 @@ NAS_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
NAS_GetAudioBuf(_THIS)
|
||||
NAS_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
NAS_CloseAudio(_THIS)
|
||||
NAS_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->aud) {
|
||||
AuCloseServer(this->hidden->aud);
|
||||
this->hidden->aud = 0;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->aud) {
|
||||
NAS_AuCloseServer(this->hidden->aud);
|
||||
this->hidden->aud = 0;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this2 = this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +268,7 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
|
||||
static AuDeviceID
|
||||
find_device(_THIS, int nch)
|
||||
{
|
||||
/* These "Au" things are all macros, not functions... */
|
||||
int i;
|
||||
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
|
||||
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
|
||||
@@ -233,46 +281,53 @@ find_device(_THIS, int nch)
|
||||
}
|
||||
|
||||
static int
|
||||
NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
NAS_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
AuElement elms[3];
|
||||
int buffer_size;
|
||||
SDL_AudioFormat test_format, format;
|
||||
|
||||
this->hidden->mixbuf = NULL;
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
format = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!format && test_format;) {
|
||||
format = sdlformat_to_auformat(test_format);
|
||||
|
||||
if (format == AuNone) {
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
}
|
||||
if (format == 0) {
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return (-1);
|
||||
NAS_CloseDevice(this);
|
||||
SDL_SetError("NAS: Couldn't find any hardware audio formats");
|
||||
return 0;
|
||||
}
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
this->hidden->aud = AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
||||
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
||||
if (this->hidden->aud == 0) {
|
||||
SDL_SetError("Couldn't open connection to NAS server");
|
||||
return (-1);
|
||||
NAS_CloseDevice(this);
|
||||
SDL_SetError("NAS: Couldn't open connection to NAS server");
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->hidden->dev = find_device(this, spec->channels);
|
||||
this->hidden->dev = find_device(this, this->spec.channels);
|
||||
if ((this->hidden->dev == AuNone)
|
||||
|| (!(this->hidden->flow = AuCreateFlow(this->hidden->aud, NULL)))) {
|
||||
AuCloseServer(this->hidden->aud);
|
||||
this->hidden->aud = 0;
|
||||
SDL_SetError("Couldn't find a fitting playback device on NAS server");
|
||||
return (-1);
|
||||
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
|
||||
NAS_CloseDevice(this);
|
||||
SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer_size = spec->freq;
|
||||
buffer_size = this->spec.freq;
|
||||
if (buffer_size < 4096)
|
||||
buffer_size = 4096;
|
||||
|
||||
@@ -280,35 +335,70 @@ NAS_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
this2 = this->hidden;
|
||||
|
||||
AuMakeElementImportClient(elms, spec->freq, format, spec->channels,
|
||||
AuMakeElementImportClient(elms,this->spec.freq,format,this->spec.channels,
|
||||
AuTrue, buffer_size, buffer_size / 4, 0, NULL);
|
||||
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, spec->freq,
|
||||
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
|
||||
AuUnlimitedSamples, 0, NULL);
|
||||
AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
|
||||
NULL);
|
||||
AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
|
||||
this->hidden->flow, event_handler,
|
||||
(AuPointer) NULL);
|
||||
NAS_AuSetElements(this->hidden->aud, this->hidden->flow,
|
||||
AuTrue, 2, elms, NULL);
|
||||
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
|
||||
this->hidden->flow, event_handler,
|
||||
(AuPointer) NULL);
|
||||
|
||||
AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
|
||||
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
this->hidden->mixlen = spec->size;
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
return (-1);
|
||||
NAS_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
this->hidden->parent = getpid();
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
NAS_Deinitialize(void)
|
||||
{
|
||||
UnloadNASLibrary();
|
||||
}
|
||||
|
||||
static int
|
||||
NAS_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
if (LoadNASLibrary() < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
|
||||
if (aud == NULL) {
|
||||
SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
|
||||
return 0;
|
||||
}
|
||||
NAS_AuCloseServer(aud);
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = NAS_OpenDevice;
|
||||
impl->PlayDevice = NAS_PlayDevice;
|
||||
impl->WaitDevice = NAS_WaitDevice;
|
||||
impl->GetDeviceBuf = NAS_GetDeviceBuf;
|
||||
impl->CloseDevice = NAS_CloseDevice;
|
||||
impl->Deinitialize = NAS_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap NAS_bootstrap = {
|
||||
NAS_DRIVER_NAME, "Network Audio System", NAS_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -46,9 +46,6 @@ struct SDL_PrivateAudioData
|
||||
AuFlowID flow;
|
||||
AuDeviceID dev;
|
||||
|
||||
/* The parent process id, to detect when application quits */
|
||||
pid_t parent;
|
||||
|
||||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
@@ -60,4 +57,5 @@ struct SDL_PrivateAudioData
|
||||
int buf_free;
|
||||
};
|
||||
#endif /* _SDL_nasaudio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -69,13 +69,13 @@ struct BuggyCards buggycards[QSA_WA_CARDS] = {
|
||||
{"Vortex 8830", QSA_MMAP_WORKAROUND},
|
||||
};
|
||||
|
||||
/* Audio driver functions */
|
||||
static void NTO_ThreadInit(_THIS);
|
||||
static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void NTO_WaitAudio(_THIS);
|
||||
static void NTO_PlayAudio(_THIS);
|
||||
static Uint8 *NTO_GetAudioBuf(_THIS);
|
||||
static void NTO_CloseAudio(_THIS);
|
||||
|
||||
static inline void
|
||||
NTO_SetError(const char *fn, int rval)
|
||||
{
|
||||
SDL_SetError("NTO: %s failed: %s", fn, snd_strerror(rval));
|
||||
}
|
||||
|
||||
|
||||
/* card names check to apply the workarounds */
|
||||
static int
|
||||
@@ -84,7 +84,7 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
|
||||
char scardname[33];
|
||||
int it;
|
||||
|
||||
if (snd_card_get_name(cardno, scardname, 32) < 0) {
|
||||
if (snd_card_get_name(this->hidden->cardno, scardname, 32) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,11 +102,10 @@ NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
|
||||
static void
|
||||
NTO_ThreadInit(_THIS)
|
||||
{
|
||||
int status;
|
||||
struct sched_param param;
|
||||
int status = SchedGet(0, 0, ¶m);
|
||||
|
||||
/* increasing default 10 priority to 25 to avoid jerky sound */
|
||||
status = SchedGet(0, 0, ¶m);
|
||||
param.sched_priority = param.sched_curpriority + 15;
|
||||
status = SchedSet(0, 0, SCHED_NOCHANGE, ¶m);
|
||||
}
|
||||
@@ -130,111 +129,26 @@ NTO_InitAudioParams(snd_pcm_channel_params_t * cpars)
|
||||
cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
|
||||
}
|
||||
|
||||
static int
|
||||
NTO_AudioAvailable(void)
|
||||
{
|
||||
/* See if we can open a nonblocking channel.
|
||||
Return value '1' means we can.
|
||||
Return value '0' means we cannot. */
|
||||
|
||||
int available;
|
||||
int rval;
|
||||
snd_pcm_t *handle;
|
||||
|
||||
available = 0;
|
||||
handle = NULL;
|
||||
|
||||
rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
|
||||
|
||||
if (rval >= 0) {
|
||||
available = 1;
|
||||
|
||||
if ((rval = snd_pcm_close(handle)) < 0) {
|
||||
SDL_SetError
|
||||
("NTO_AudioAvailable(): snd_pcm_close failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
available = 0;
|
||||
}
|
||||
} else {
|
||||
SDL_SetError
|
||||
("NTO_AudioAvailable(): there are no available audio devices.\n");
|
||||
}
|
||||
|
||||
return (available);
|
||||
}
|
||||
|
||||
static void
|
||||
NTO_DeleteAudioDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
if ((device) && (device->hidden)) {
|
||||
SDL_free(device->hidden);
|
||||
}
|
||||
if (device) {
|
||||
SDL_free(device);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
NTO_CreateAudioDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, sizeof(SDL_AudioDevice));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc(sizeof(struct SDL_PrivateAudioData));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
|
||||
audio_handle = NULL;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->ThreadInit = NTO_ThreadInit;
|
||||
this->OpenAudio = NTO_OpenAudio;
|
||||
this->WaitAudio = NTO_WaitAudio;
|
||||
this->PlayAudio = NTO_PlayAudio;
|
||||
this->GetAudioBuf = NTO_GetAudioBuf;
|
||||
this->CloseAudio = NTO_CloseAudio;
|
||||
|
||||
this->free = NTO_DeleteAudioDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap QNXNTOAUDIO_bootstrap = {
|
||||
DRIVER_NAME, "QNX6 QSA-NTO Audio",
|
||||
NTO_AudioAvailable,
|
||||
NTO_CreateAudioDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
NTO_WaitAudio(_THIS)
|
||||
NTO_WaitDevice(_THIS)
|
||||
{
|
||||
fd_set wfds;
|
||||
int selectret;
|
||||
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(audio_fd, &wfds);
|
||||
FD_SET(this->hidden->audio_fd, &wfds);
|
||||
|
||||
do {
|
||||
selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL);
|
||||
selectret = select(this->hidden->audio_fd+1, NULL, &wfds, NULL, NULL);
|
||||
switch (selectret) {
|
||||
case -1:
|
||||
case 0:
|
||||
SDL_SetError("NTO_WaitAudio(): select() failed: %s\n",
|
||||
strerror(errno));
|
||||
SDL_SetError("NTO: select() failed: %s\n", strerror(errno));
|
||||
return;
|
||||
default:
|
||||
if (FD_ISSET(audio_fd, &wfds)) {
|
||||
if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -244,22 +158,24 @@ NTO_WaitAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
NTO_PlayAudio(_THIS)
|
||||
NTO_PlayDevice(_THIS)
|
||||
{
|
||||
snd_pcm_channel_status_t cstatus;
|
||||
int written, rval;
|
||||
int towrite;
|
||||
void *pcmbuffer;
|
||||
|
||||
if (!this->enabled) {
|
||||
if ((!this->enabled) || (!this->hidden)) {
|
||||
return;
|
||||
}
|
||||
|
||||
towrite = this->spec.size;
|
||||
pcmbuffer = pcm_buf;
|
||||
pcmbuffer = this->hidden->pcm_buf;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
|
||||
do {
|
||||
written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
|
||||
written = snd_pcm_plugin_write(this->hidden->audio_handle,
|
||||
pcmbuffer, towrite);
|
||||
if (written != towrite) {
|
||||
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
|
||||
/* Let a little CPU time go by and try to write again */
|
||||
@@ -268,33 +184,28 @@ NTO_PlayAudio(_THIS)
|
||||
towrite -= written;
|
||||
pcmbuffer += written * this->spec.channels;
|
||||
continue;
|
||||
} else {
|
||||
if ((errno == EINVAL) || (errno == EIO)) {
|
||||
SDL_memset(&cstatus, 0, sizeof(cstatus));
|
||||
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||
if ((rval =
|
||||
snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) {
|
||||
SDL_SetError
|
||||
("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
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 {
|
||||
} else if ((errno == EINVAL) || (errno == EIO)) {
|
||||
SDL_memset(&cstatus, 0, sizeof (cstatus));
|
||||
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||
rval = snd_pcm_plugin_status(this->hidden->audio_handle,
|
||||
&cstatus);
|
||||
if (rval < 0) {
|
||||
NTO_SetError("snd_pcm_plugin_status", rval);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
|
||||
(cstatus.status == SND_PCM_STATUS_READY)) {
|
||||
rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (rval < 0) {
|
||||
NTO_SetError("snd_pcm_plugin_prepare", rval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* we wrote all remaining data */
|
||||
@@ -308,77 +219,74 @@ NTO_PlayAudio(_THIS)
|
||||
if (towrite != 0) {
|
||||
this->enabled = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
NTO_GetAudioBuf(_THIS)
|
||||
NTO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return pcm_buf;
|
||||
return this->hidden->pcm_buf;
|
||||
}
|
||||
|
||||
static void
|
||||
NTO_CloseAudio(_THIS)
|
||||
NTO_CloseDevice(_THIS)
|
||||
{
|
||||
int rval;
|
||||
|
||||
this->enabled = 0;
|
||||
|
||||
if (audio_handle != NULL) {
|
||||
if ((rval =
|
||||
snd_pcm_plugin_flush(audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK)) < 0) {
|
||||
SDL_SetError
|
||||
("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->audio_handle != NULL) {
|
||||
snd_pcm_plugin_flush(this->hidden->audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK);
|
||||
snd_pcm_close(this->hidden->audio_handle);
|
||||
this->hidden->audio_handle = NULL;
|
||||
}
|
||||
if ((rval = snd_pcm_close(audio_handle)) < 0) {
|
||||
SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return;
|
||||
if (this->hidden->pcm_buf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->pcm_buf);
|
||||
this->hidden->pcm_buf = NULL;
|
||||
}
|
||||
audio_handle = NULL;
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
NTO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
int rval;
|
||||
int format;
|
||||
SDL_AudioFormat test_format;
|
||||
int found;
|
||||
int rval = 0;
|
||||
int format = 0;
|
||||
SDL_AudioFormat test_format = 0;
|
||||
int found = 0;
|
||||
snd_pcm_channel_setup_t csetup;
|
||||
snd_pcm_channel_params_t cparams;
|
||||
|
||||
audio_handle = NULL;
|
||||
this->enabled = 0;
|
||||
|
||||
if (pcm_buf != NULL) {
|
||||
SDL_FreeAudioMem(pcm_buf);
|
||||
pcm_buf = NULL;
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* initialize channel transfer parameters to default */
|
||||
NTO_InitAudioParams(&cparams);
|
||||
|
||||
/* Open the audio device */
|
||||
rval =
|
||||
snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
|
||||
rval = snd_pcm_open_preferred(&this->hidden->audio_handle,
|
||||
&this->hidden->cardno,
|
||||
&this->hidden->deviceno, OPEN_FLAGS);
|
||||
|
||||
if (rval < 0) {
|
||||
SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return (-1);
|
||||
NTO_CloseDevice(this);
|
||||
NTO_SetError("snd_pcm_open", rval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
|
||||
/* enable count status parameter */
|
||||
if ((rval =
|
||||
snd_pcm_plugin_set_disable(audio_handle,
|
||||
PLUGIN_DISABLE_MMAP)) < 0) {
|
||||
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return (-1);
|
||||
rval = snd_pcm_plugin_set_disable(this->hidden->audio_handle,
|
||||
PLUGIN_DISABLE_MMAP);
|
||||
if (rval < 0) {
|
||||
NTO_CloseDevice(this);
|
||||
NTO_SetError("snd_pcm_plugin_set_disable", rval);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,7 +295,7 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
/* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
|
||||
found = 0;
|
||||
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format); !found;) {
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
|
||||
/* if match found set format to equivalent ALSA format */
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
@@ -441,86 +349,115 @@ NTO_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
/* assumes test_format not 0 on success */
|
||||
if (test_format == 0) {
|
||||
SDL_SetError
|
||||
("NTO_OpenAudio(): Couldn't find any hardware audio formats");
|
||||
return (-1);
|
||||
NTO_CloseDevice(this);
|
||||
SDL_SetError("NTO: Couldn't find any hardware audio formats");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
/* Set the audio format */
|
||||
cparams.format.format = format;
|
||||
|
||||
/* Set mono or stereo audio (currently only two channels supported) */
|
||||
cparams.format.voices = spec->channels;
|
||||
cparams.format.voices = this->spec.channels;
|
||||
|
||||
/* Set rate */
|
||||
cparams.format.rate = spec->freq;
|
||||
cparams.format.rate = this->spec.freq;
|
||||
|
||||
/* Setup the transfer parameters according to cparams */
|
||||
rval = snd_pcm_plugin_params(audio_handle, &cparams);
|
||||
rval = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
|
||||
if (rval < 0) {
|
||||
SDL_SetError
|
||||
("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return (-1);
|
||||
NTO_CloseDevice(this);
|
||||
NTO_SetError("snd_pcm_channel_params", rval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure channel is setup right one last time */
|
||||
SDL_memset(&csetup, 0x00, sizeof(csetup));
|
||||
SDL_memset(&csetup, '\0', sizeof (csetup));
|
||||
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||
if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) {
|
||||
SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
|
||||
return -1;
|
||||
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
|
||||
NTO_CloseDevice(this);
|
||||
SDL_SetError("NTO: Unable to setup playback channel\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
pcm_len = spec->size;
|
||||
this->hidden->pcm_len = this->spec.size;
|
||||
|
||||
if (pcm_len == 0) {
|
||||
pcm_len =
|
||||
csetup.buf.block.frag_size * spec->channels *
|
||||
if (this->hidden->pcm_len == 0) {
|
||||
this->hidden->pcm_len =
|
||||
csetup.buf.block.frag_size * this->spec.channels *
|
||||
(snd_pcm_format_width(format) / 8);
|
||||
}
|
||||
|
||||
/* Allocate memory to the audio buffer and initialize with silence (Note that
|
||||
buffer size must be a multiple of fragment size, so find closest multiple)
|
||||
/*
|
||||
* Allocate memory to the audio buffer and initialize with silence
|
||||
* (Note that buffer size must be a multiple of fragment size, so find
|
||||
* closest multiple)
|
||||
*/
|
||||
pcm_buf = (Uint8 *) SDL_AllocAudioMem(pcm_len);
|
||||
if (pcm_buf == NULL) {
|
||||
SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
|
||||
return (-1);
|
||||
this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
|
||||
if (this->hidden->pcm_buf == NULL) {
|
||||
NTO_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(pcm_buf, spec->silence, pcm_len);
|
||||
SDL_memset(this->hidden->pcm_buf,this->spec.silence,this->hidden->pcm_len);
|
||||
|
||||
/* get the file descriptor */
|
||||
if ((audio_fd =
|
||||
snd_pcm_file_descriptor(audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK)) < 0) {
|
||||
SDL_SetError
|
||||
("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n",
|
||||
snd_strerror(rval));
|
||||
return (-1);
|
||||
this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (this->hidden->audio_fd < 0) {
|
||||
NTO_CloseDevice(this);
|
||||
NTO_SetError("snd_pcm_file_descriptor", rval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Trigger audio playback */
|
||||
rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
rval = snd_pcm_plugin_prepare(this->hidden->audio_handle,
|
||||
SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (rval < 0) {
|
||||
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",
|
||||
snd_strerror(rval));
|
||||
return (-1);
|
||||
NTO_CloseDevice(this);
|
||||
NTO_SetError("snd_pcm_plugin_prepare", rval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->enabled = 1;
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
|
||||
/* We're really ready to rock and roll. :-) */
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
NTO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* See if we can open a nonblocking channel. */
|
||||
snd_pcm_t *handle = NULL;
|
||||
int rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
|
||||
if (rval < 0) {
|
||||
SDL_SetError("NTO: couldn't open preferred audio device");
|
||||
return 0;
|
||||
}
|
||||
if ((rval = snd_pcm_close(handle)) < 0) {
|
||||
SDL_SetError("NTO: couldn't close test audio device");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = NTO_OpenDevice;
|
||||
impl->ThreadInit = NTO_ThreadInit;
|
||||
impl->WaitDevice = NTO_WaitDevice;
|
||||
impl->PlayDevice = NTO_PlayDevice;
|
||||
impl->GetDeviceBuf = NTO_GetDeviceBuf;
|
||||
impl->CloseDevice = NTO_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap QNXNTOAUDIO_bootstrap = {
|
||||
DRIVER_NAME, "QNX6 QSA-NTO Audio", NTO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -47,23 +47,7 @@ struct SDL_PrivateAudioData
|
||||
/* Raw mixing buffer */
|
||||
Uint8 *pcm_buf;
|
||||
Uint32 pcm_len;
|
||||
|
||||
/* QSA parameters */
|
||||
snd_pcm_channel_status_t cstatus;
|
||||
snd_pcm_channel_params_t cparams;
|
||||
snd_pcm_channel_setup_t csetup;
|
||||
};
|
||||
|
||||
#define cardno (this->hidden->cardno)
|
||||
#define deviceno (this->hidden->deviceno)
|
||||
#define audio_handle (this->hidden->audio_handle)
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define pcm_buf (this->hidden->pcm_buf)
|
||||
#define pcm_len (this->hidden->pcm_len)
|
||||
#define cstatus (this->hidden->cstatus)
|
||||
#define cparams (this->hidden->cparams)
|
||||
#define csetup (this->hidden->csetup)
|
||||
|
||||
#endif /* __SDL_NTO_AUDIO_H__ */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -30,16 +30,17 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "../SDL_audiomem.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_paudio.h"
|
||||
|
||||
#define DEBUG_AUDIO 1
|
||||
#define DEBUG_AUDIO 0
|
||||
|
||||
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
|
||||
* I guess nobody ever uses audio... Shame over AIX header files. */
|
||||
@@ -48,94 +49,95 @@
|
||||
#include <sys/audio.h>
|
||||
|
||||
/* The tag name used by paud audio */
|
||||
#define Paud_DRIVER_NAME "paud"
|
||||
#define PAUDIO_DRIVER_NAME "paud"
|
||||
|
||||
/* Open the audio device for playback, and don't block if busy */
|
||||
/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
|
||||
#define OPEN_FLAGS O_WRONLY
|
||||
|
||||
/* Audio driver functions */
|
||||
static int Paud_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void Paud_WaitAudio(_THIS);
|
||||
static void Paud_PlayAudio(_THIS);
|
||||
static Uint8 *Paud_GetAudioBuf(_THIS);
|
||||
static void Paud_CloseAudio(_THIS);
|
||||
/* Get the name of the audio device we use for output */
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
#ifndef _PATH_DEV_DSP
|
||||
#define _PATH_DEV_DSP "/dev/%caud%c/%c"
|
||||
#endif
|
||||
|
||||
static char devsettings[][3] = {
|
||||
{'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
|
||||
{'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
|
||||
{'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
|
||||
{'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
|
||||
{'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
|
||||
{'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
|
||||
{'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
|
||||
{'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
|
||||
{'\0', '\0', '\0'}
|
||||
};
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
OpenUserDefinedDevice(char *path, int maxlen, int flags)
|
||||
{
|
||||
const char *audiodev;
|
||||
int fd;
|
||||
int available;
|
||||
|
||||
available = 0;
|
||||
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
|
||||
if (fd >= 0) {
|
||||
available = 1;
|
||||
close(fd);
|
||||
/* Figure out what our audio device is */
|
||||
if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
|
||||
audiodev = SDL_getenv("AUDIODEV");
|
||||
}
|
||||
return (available);
|
||||
if (audiodev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
fd = open(audiodev, flags, 0);
|
||||
if (path != NULL) {
|
||||
SDL_strlcpy(path, audiodev, maxlen);
|
||||
path[maxlen - 1] = '\0';
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
static int
|
||||
OpenAudioPath(char *path, int maxlen, int flags, int classic)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
struct stat sb;
|
||||
int cycle = 0;
|
||||
int fd = OpenUserDefinedDevice(path, maxlen, flags);
|
||||
|
||||
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 (fd != -1) {
|
||||
return fd;
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
|
||||
/* !!! FIXME: do we really need a table here? */
|
||||
while (devsettings[cycle][0] != '\0') {
|
||||
char audiopath[1024];
|
||||
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
|
||||
_PATH_DEV_DSP,
|
||||
devsettings[cycle][0],
|
||||
devsettings[cycle][1], devsettings[cycle][2]);
|
||||
|
||||
if (stat(audiopath, &sb) == 0) {
|
||||
fd = open(audiopath, flags, 0);
|
||||
if (fd > 0) {
|
||||
if (path != NULL) {
|
||||
SDL_strlcpy(path, audiopath, maxlen);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
audio_fd = -1;
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Paud_OpenAudio;
|
||||
this->WaitAudio = Paud_WaitAudio;
|
||||
this->PlayAudio = Paud_PlayAudio;
|
||||
this->GetAudioBuf = Paud_GetAudioBuf;
|
||||
this->CloseAudio = Paud_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioBootStrap Paud_bootstrap = {
|
||||
Paud_DRIVER_NAME, "AIX Paudio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
Paud_WaitAudio(_THIS)
|
||||
PAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
fd_set fdset;
|
||||
|
||||
/* See if we need to use timed audio synchronization */
|
||||
if (frame_ticks) {
|
||||
if (this->hidden->frame_ticks) {
|
||||
/* Use timer for general audio synchronization */
|
||||
Sint32 ticks;
|
||||
|
||||
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
|
||||
ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
|
||||
if (ticks > 0) {
|
||||
SDL_Delay(ticks);
|
||||
}
|
||||
@@ -145,9 +147,9 @@ Paud_WaitAudio(_THIS)
|
||||
/* Use select() for audio synchronization */
|
||||
struct timeval timeout;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(audio_fd, &fdset);
|
||||
FD_SET(this->hidden->audio_fd, &fdset);
|
||||
|
||||
if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
||||
if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Couldn't get audio buffer information\n");
|
||||
#endif
|
||||
@@ -168,7 +170,7 @@ Paud_WaitAudio(_THIS)
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Waiting for audio to get ready\n");
|
||||
#endif
|
||||
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
|
||||
if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) {
|
||||
const char *message =
|
||||
"Audio timeout - buggy audio driver? (disabled)";
|
||||
/*
|
||||
@@ -179,7 +181,7 @@ Paud_WaitAudio(_THIS)
|
||||
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
|
||||
this->enabled = 0;
|
||||
/* Don't try to close - may hang */
|
||||
audio_fd = -1;
|
||||
this->hidden->audio_fd = -1;
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Done disabling audio\n");
|
||||
#endif
|
||||
@@ -191,13 +193,15 @@ Paud_WaitAudio(_THIS)
|
||||
}
|
||||
|
||||
static void
|
||||
Paud_PlayAudio(_THIS)
|
||||
PAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
int written;
|
||||
int written = 0;
|
||||
const Uint8 *mixbuf = this->hidden->mixbuf;
|
||||
const size_t mixlen = this->hidden->mixlen;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||
do {
|
||||
written = write(audio_fd, mixbuf, mixlen);
|
||||
written = write(this->hidden->audio_fd, mixbuf, mixlen);
|
||||
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
|
||||
SDL_Delay(1); /* Let a little CPU time go by */
|
||||
}
|
||||
@@ -206,8 +210,8 @@ Paud_PlayAudio(_THIS)
|
||||
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
|
||||
|
||||
/* If timer synchronization is enabled, set the next write frame */
|
||||
if (frame_ticks) {
|
||||
next_frame += frame_ticks;
|
||||
if (this->hidden->frame_ticks) {
|
||||
this->hidden->next_frame += this->hidden->frame_ticks;
|
||||
}
|
||||
|
||||
/* If we couldn't write, assume fatal error for now */
|
||||
@@ -220,28 +224,34 @@ Paud_PlayAudio(_THIS)
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
Paud_GetAudioBuf(_THIS)
|
||||
PAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return mixbuf;
|
||||
return this->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
Paud_CloseAudio(_THIS)
|
||||
PAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if (mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(mixbuf);
|
||||
mixbuf = NULL;
|
||||
}
|
||||
if (audio_fd >= 0) {
|
||||
close(audio_fd);
|
||||
audio_fd = -1;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
SDL_FreeAudioMem(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
if (this->hidden->audio_fd >= 0) {
|
||||
close(this->hidden->audio_fd);
|
||||
this->hidden->audio_fd = -1;
|
||||
}
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
|
||||
char audiodev[1024];
|
||||
const char *err = NULL;
|
||||
int format;
|
||||
int bytes_per_sample;
|
||||
SDL_AudioFormat test_format;
|
||||
@@ -250,32 +260,40 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
audio_status paud_status;
|
||||
audio_control paud_control;
|
||||
audio_change paud_change;
|
||||
int fd = -1;
|
||||
|
||||
/* Reset the timer synchronization flag */
|
||||
frame_ticks = 0.0;
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Open the audio device */
|
||||
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
|
||||
if (audio_fd < 0) {
|
||||
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
|
||||
this->hidden->audio_fd = fd;
|
||||
if (fd < 0) {
|
||||
PAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't set the buffer size - just ask the device for the maximum
|
||||
* that we can have.
|
||||
*/
|
||||
if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
||||
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
|
||||
PAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Couldn't get audio buffer information");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mixbuf = NULL;
|
||||
|
||||
if (spec->channels > 1)
|
||||
spec->channels = 2;
|
||||
if (this->spec.channels > 1)
|
||||
this->spec.channels = 2;
|
||||
else
|
||||
spec->channels = 1;
|
||||
this->spec.channels = 1;
|
||||
|
||||
/*
|
||||
* Fields in the audio_init structure:
|
||||
@@ -322,14 +340,14 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
* paud.position_resolution; * smallest increment for position
|
||||
*/
|
||||
|
||||
paud_init.srate = spec->freq;
|
||||
paud_init.srate = this->spec.freq;
|
||||
paud_init.mode = PCM;
|
||||
paud_init.operation = PLAY;
|
||||
paud_init.channels = spec->channels;
|
||||
paud_init.channels = this->spec.channels;
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
format = 0;
|
||||
for (test_format = SDL_FirstAudioFormat(spec->format);
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
!format && test_format;) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
@@ -382,31 +400,32 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Couldn't find any hardware audio formats\n");
|
||||
#endif
|
||||
PAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Couldn't find any hardware audio formats");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
spec->format = test_format;
|
||||
this->spec.format = test_format;
|
||||
|
||||
/*
|
||||
* We know the buffer size and the max number of subsequent writes
|
||||
* that can be pending. If more than one can pend, allow the application
|
||||
* to do something like double buffering between our write buffer and
|
||||
* the device's own buffer that we are filling with write() anyway.
|
||||
* that can be pending. If more than one can pend, allow the application
|
||||
* to do something like double buffering between our write buffer and
|
||||
* the device's own buffer that we are filling with write() anyway.
|
||||
*
|
||||
* We calculate spec->samples like this because SDL_CalculateAudioSpec()
|
||||
* will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
|
||||
* into spec->size in return.
|
||||
* We calculate this->spec.samples like this because
|
||||
* SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
|
||||
* (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
|
||||
*/
|
||||
if (paud_bufinfo.request_buf_cap == 1) {
|
||||
spec->samples = paud_bufinfo.write_buf_cap
|
||||
/ bytes_per_sample / spec->channels;
|
||||
this->spec.samples = paud_bufinfo.write_buf_cap
|
||||
/ bytes_per_sample / this->spec.channels;
|
||||
} else {
|
||||
spec->samples = paud_bufinfo.write_buf_cap
|
||||
/ bytes_per_sample / spec->channels / 2;
|
||||
this->spec.samples = paud_bufinfo.write_buf_cap
|
||||
/ bytes_per_sample / this->spec.channels / 2;
|
||||
}
|
||||
paud_init.bsize = bytes_per_sample * spec->channels;
|
||||
paud_init.bsize = bytes_per_sample * this->spec.channels;
|
||||
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/*
|
||||
* The AIX paud device init can't modify the values of the audio_init
|
||||
@@ -416,47 +435,44 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
* /dev/paud supports all of the encoding formats, so we don't need
|
||||
* to do anything like reopening the device, either.
|
||||
*/
|
||||
if (ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0) {
|
||||
if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
|
||||
switch (paud_init.rc) {
|
||||
case 1:
|
||||
SDL_SetError
|
||||
("Couldn't set audio format: DSP can't do play requests");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: DSP can't do play requests";
|
||||
break;
|
||||
case 2:
|
||||
SDL_SetError
|
||||
("Couldn't set audio format: DSP can't do record requests");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: DSP can't do record requests";
|
||||
break;
|
||||
case 4:
|
||||
SDL_SetError("Couldn't set audio format: request was invalid");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: request was invalid";
|
||||
break;
|
||||
case 5:
|
||||
SDL_SetError
|
||||
("Couldn't set audio format: conflict with open's flags");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: conflict with open's flags";
|
||||
break;
|
||||
case 6:
|
||||
SDL_SetError
|
||||
("Couldn't set audio format: out of DSP MIPS or memory");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: out of DSP MIPS or memory";
|
||||
break;
|
||||
default:
|
||||
SDL_SetError
|
||||
("Couldn't set audio format: not documented in sys/audio.h");
|
||||
return -1;
|
||||
err = "Couldn't set audio format: not documented in sys/audio.h";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
mixlen = spec->size;
|
||||
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
|
||||
if (mixbuf == NULL) {
|
||||
return -1;
|
||||
if (err != NULL) {
|
||||
PAUDIO_CloseDevice(this);
|
||||
SDL_SetError("Paudio: %s", err);
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(mixbuf, spec->silence, spec->size);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
PAUDIO_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
/*
|
||||
* Set some paramters: full volume, first speaker that we can find.
|
||||
@@ -475,7 +491,7 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
|
||||
paud_control.ioctl_request = AUDIO_CHANGE;
|
||||
paud_control.request_info = (char *) &paud_change;
|
||||
if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) {
|
||||
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Can't change audio display settings\n");
|
||||
#endif
|
||||
@@ -487,29 +503,49 @@ Paud_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
*/
|
||||
paud_control.ioctl_request = AUDIO_START;
|
||||
paud_control.position = 0;
|
||||
if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) {
|
||||
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
|
||||
PAUDIO_CloseDevice(this);
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Can't start audio play\n");
|
||||
#endif
|
||||
SDL_SetError("Can't start audio play");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check to see if we need to use select() workaround */
|
||||
{
|
||||
char *workaround;
|
||||
workaround = SDL_getenv("SDL_DSP_NOSELECT");
|
||||
if (workaround) {
|
||||
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
|
||||
next_frame = SDL_GetTicks() + frame_ticks;
|
||||
}
|
||||
if (workaround != NULL) {
|
||||
this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
|
||||
this->spec.freq;
|
||||
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
|
||||
}
|
||||
|
||||
/* Get the parent process id (we're the parent of the audio thread) */
|
||||
parent = getpid();
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
PAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
|
||||
if (fd < 0) {
|
||||
SDL_SetError("PAUDIO: Couldn't open audio device");
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = DSP_OpenDevice;
|
||||
impl->PlayDevice = DSP_PlayDevice;
|
||||
impl->PlayDevice = DSP_WaitDevice;
|
||||
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
||||
impl->CloseDevice = DSP_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap PAUDIO_bootstrap = {
|
||||
PAUDIO_DRIVER_NAME, "AIX Paudio", PAUDIO_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -34,9 +34,6 @@ struct SDL_PrivateAudioData
|
||||
/* The file descriptor for the audio device */
|
||||
int audio_fd;
|
||||
|
||||
/* The parent process id, to detect when application quits */
|
||||
pid_t parent;
|
||||
|
||||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
@@ -47,13 +44,5 @@ struct SDL_PrivateAudioData
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
/* Old variable names */
|
||||
#define audio_fd (this->hidden->audio_fd)
|
||||
#define parent (this->hidden->parent)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define frame_ticks (this->hidden->frame_ticks)
|
||||
#define next_frame (this->hidden->next_frame)
|
||||
|
||||
#endif /* _SDL_paudaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/* I'm gambling no one uses this audio backend...we'll see who emails. :) */
|
||||
#error this code has not been updated for SDL 1.3.
|
||||
#error if no one emails icculus at icculus.org and tells him that this
|
||||
#error code is needed, this audio backend will eventually be removed from SDL.
|
||||
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2006 Sam Lantinga
|
||||
@@ -116,7 +121,7 @@ Audio_CreateDevice(int devindex)
|
||||
|
||||
AudioBootStrap SUNAUDIO_bootstrap = {
|
||||
"audio", "UNIX /dev/audio interface",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
Audio_Available, Audio_CreateDevice, 0
|
||||
};
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_sunaudio_h
|
||||
#define _SDL_sunaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
@@ -53,5 +53,6 @@ struct SDL_PrivateAudioData
|
||||
#define fragsize (this->hidden->fragsize)
|
||||
#define frequency (this->hidden->frequency)
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
#endif /* _SDL_sunaudio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/* I'm gambling no one uses this audio backend...we'll see who emails. :) */
|
||||
#error this code has not been updated for SDL 1.3.
|
||||
#error if no one emails icculus at icculus.org and tells him that this
|
||||
#error code is needed, this audio backend will eventually be removed from SDL.
|
||||
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2006 Sam Lantinga
|
||||
@@ -36,7 +41,6 @@
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_umsaudio.h"
|
||||
|
||||
/* The tag name used by UMS audio */
|
||||
@@ -152,7 +156,7 @@ Audio_CreateDevice(int devindex)
|
||||
|
||||
AudioBootStrap UMS_bootstrap = {
|
||||
UMS_DRIVER_NAME, "AIX UMS audio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
Audio_Available, Audio_CreateDevice, 0
|
||||
};
|
||||
|
||||
static Uint8 *
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
|
||||
@@ -35,71 +35,13 @@
|
||||
#include "win_ce_semaphore.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DIB_ThreadInit(_THIS);
|
||||
static void DIB_WaitAudio(_THIS);
|
||||
static Uint8 *DIB_GetAudioBuf(_THIS);
|
||||
static void DIB_PlayAudio(_THIS);
|
||||
static void DIB_WaitDone(_THIS);
|
||||
static void DIB_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Audio_DeleteDevice(SDL_AudioDevice * device)
|
||||
{
|
||||
SDL_free(device->hidden);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
|
||||
if (this) {
|
||||
SDL_memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ((this == NULL) || (this->hidden == NULL)) {
|
||||
SDL_OutOfMemory();
|
||||
if (this) {
|
||||
SDL_free(this);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = DIB_OpenAudio;
|
||||
this->ThreadInit = DIB_ThreadInit;
|
||||
this->WaitAudio = DIB_WaitAudio;
|
||||
this->PlayAudio = DIB_PlayAudio;
|
||||
this->GetAudioBuf = DIB_GetAudioBuf;
|
||||
this->WaitDone = DIB_WaitDone;
|
||||
this->CloseAudio = DIB_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap WAVEOUT_bootstrap = {
|
||||
"waveout", "Win95/98/NT/2000 WaveOut",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
|
||||
#elif defined(WIN64)
|
||||
#define WINDOWS_OS_NAME "Win64"
|
||||
#else
|
||||
#define WINDOWS_OS_NAME "Win32"
|
||||
#endif
|
||||
|
||||
/* The Win32 callback for filling the WAVE device */
|
||||
static void CALLBACK
|
||||
@@ -114,9 +56,9 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
|
||||
|
||||
/* Signal that we are done playing a buffer */
|
||||
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
|
||||
ReleaseSemaphoreCE(audio_sem, 1, NULL);
|
||||
ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
|
||||
#else
|
||||
ReleaseSemaphore(audio_sem, 1, NULL);
|
||||
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -146,48 +88,47 @@ SetMMerror(char *function, MMRESULT code)
|
||||
|
||||
/* Set high priority for the audio thread */
|
||||
static void
|
||||
DIB_ThreadInit(_THIS)
|
||||
WINWAVEOUT_ThreadInit(_THIS)
|
||||
{
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
|
||||
void
|
||||
DIB_WaitAudio(_THIS)
|
||||
WINWAVEOUT_WaitDevice(_THIS)
|
||||
{
|
||||
/* Wait for an audio chunk to finish */
|
||||
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
|
||||
WaitForSemaphoreCE(audio_sem, INFINITE);
|
||||
WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
|
||||
#else
|
||||
WaitForSingleObject(audio_sem, INFINITE);
|
||||
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
Uint8 *
|
||||
DIB_GetAudioBuf(_THIS)
|
||||
WINWAVEOUT_GetDeviceBuf(_THIS)
|
||||
{
|
||||
Uint8 *retval;
|
||||
|
||||
retval = (Uint8 *) (wavebuf[next_buffer].lpData);
|
||||
return retval;
|
||||
return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData);
|
||||
}
|
||||
|
||||
void
|
||||
DIB_PlayAudio(_THIS)
|
||||
WINWAVEOUT_PlayDevice(_THIS)
|
||||
{
|
||||
/* Queue it up */
|
||||
waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
|
||||
next_buffer = (next_buffer + 1) % NUM_BUFFERS;
|
||||
waveOutWrite(this->hidden->sound,
|
||||
&this->hidden->wavebuf[this->hidden->next_buffer],
|
||||
sizeof (this->hidden->wavebuf[0]));
|
||||
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
|
||||
void
|
||||
DIB_WaitDone(_THIS)
|
||||
WINWAVEOUT_WaitDone(_THIS)
|
||||
{
|
||||
int i, left;
|
||||
|
||||
do {
|
||||
left = NUM_BUFFERS;
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
if (wavebuf[i].dwFlags & WHDR_DONE) {
|
||||
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
|
||||
--left;
|
||||
}
|
||||
}
|
||||
@@ -199,143 +140,197 @@ DIB_WaitDone(_THIS)
|
||||
}
|
||||
|
||||
void
|
||||
DIB_CloseAudio(_THIS)
|
||||
WINWAVEOUT_CloseDevice(_THIS)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Close up audio */
|
||||
if (audio_sem) {
|
||||
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
|
||||
CloseSynchHandle(audio_sem);
|
||||
#else
|
||||
CloseHandle(audio_sem);
|
||||
#endif
|
||||
}
|
||||
if (sound) {
|
||||
waveOutClose(sound);
|
||||
}
|
||||
if (this->hidden != NULL) {
|
||||
int i;
|
||||
|
||||
/* Clean up mixing buffers */
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
if (wavebuf[i].dwUser != 0xFFFF) {
|
||||
waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
|
||||
wavebuf[i].dwUser = 0xFFFF;
|
||||
if (this->hidden->audio_sem) {
|
||||
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
|
||||
CloseSynchHandle(this->hidden->audio_sem);
|
||||
#else
|
||||
CloseHandle(this->hidden->audio_sem);
|
||||
#endif
|
||||
this->hidden->audio_sem = 0;
|
||||
}
|
||||
}
|
||||
/* Free raw mixing buffer */
|
||||
if (mixbuf != NULL) {
|
||||
SDL_free(mixbuf);
|
||||
mixbuf = NULL;
|
||||
|
||||
if (this->hidden->sound) {
|
||||
waveOutClose(this->hidden->sound);
|
||||
this->hidden->sound = 0;
|
||||
}
|
||||
|
||||
/* Clean up mixing buffers */
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
|
||||
waveOutUnprepareHeader(this->hidden->sound,
|
||||
&this->hidden->wavebuf[i],
|
||||
sizeof (this->hidden->wavebuf[i]));
|
||||
this->hidden->wavebuf[i].dwUser = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
/* Free raw mixing buffer */
|
||||
SDL_free(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
DIB_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
int valid_datatype = 0;
|
||||
MMRESULT result;
|
||||
int i;
|
||||
WAVEFORMATEX waveformat;
|
||||
int i;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Initialize the wavebuf structures for closing */
|
||||
sound = NULL;
|
||||
audio_sem = NULL;
|
||||
for (i = 0; i < NUM_BUFFERS; ++i)
|
||||
wavebuf[i].dwUser = 0xFFFF;
|
||||
mixbuf = NULL;
|
||||
this->hidden->wavebuf[i].dwUser = 0xFFFF;
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
valid_datatype = 1;
|
||||
_this->spec.format = test_format;
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S16:
|
||||
case AUDIO_S32:
|
||||
break; /* valid. */
|
||||
|
||||
default:
|
||||
valid_datatype = 0;
|
||||
test_format = SDL_NextAudioFormat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_datatype) {
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set basic WAVE format parameters */
|
||||
SDL_memset(&waveformat, 0, sizeof(waveformat));
|
||||
SDL_memset(&waveformat, '\0', sizeof (waveformat));
|
||||
waveformat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
|
||||
/* Determine the audio parameters from the AudioSpec */
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
case 8:
|
||||
/* Unsigned 8 bit audio data */
|
||||
spec->format = AUDIO_U8;
|
||||
waveformat.wBitsPerSample = 8;
|
||||
break;
|
||||
case 16:
|
||||
/* Signed 16 bit audio data */
|
||||
spec->format = AUDIO_S16;
|
||||
waveformat.wBitsPerSample = 16;
|
||||
break;
|
||||
case 32:
|
||||
/* Signed 32 bit audio data */
|
||||
spec->format = AUDIO_S32;
|
||||
waveformat.wBitsPerSample = 32;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
}
|
||||
waveformat.nChannels = spec->channels;
|
||||
waveformat.nSamplesPerSec = spec->freq;
|
||||
if (this->spec.channels > 2)
|
||||
this->spec.channels = 2; /* !!! FIXME: is this right? */
|
||||
|
||||
waveformat.nChannels = this->spec.channels;
|
||||
waveformat.nSamplesPerSec = this->spec.freq;
|
||||
waveformat.nBlockAlign =
|
||||
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
|
||||
waveformat.nAvgBytesPerSec =
|
||||
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
|
||||
|
||||
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
|
||||
if (spec->samples < (spec->freq / 4))
|
||||
spec->samples = ((spec->freq / 4) + 3) & ~3;
|
||||
if (this->spec.samples < (this->spec.freq / 4))
|
||||
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Open the audio device */
|
||||
result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
|
||||
result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
|
||||
(DWORD_PTR) FillSound, (DWORD_PTR) this,
|
||||
CALLBACK_FUNCTION);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SetMMerror("waveOutOpen()", result);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
#ifdef SOUND_DEBUG
|
||||
/* Check the sound device we retrieved */
|
||||
{
|
||||
WAVEOUTCAPS caps;
|
||||
|
||||
result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps));
|
||||
result = waveOutGetDevCaps((UINT) this->hidden->sound,
|
||||
&caps, sizeof(caps));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SetMMerror("waveOutGetDevCaps()", result);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
printf("Audio device: %s\n", caps.szPname);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create the audio buffer semaphore */
|
||||
this->hidden->audio_sem =
|
||||
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
|
||||
audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
||||
CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
||||
#else
|
||||
audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
||||
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
|
||||
#endif
|
||||
if (audio_sem == NULL) {
|
||||
if (this->hidden->audio_sem == NULL) {
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SDL_SetError("Couldn't create semaphore");
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the sound buffers */
|
||||
mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * spec->size);
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
|
||||
if (mixbuf == NULL) {
|
||||
SDL_SetError("Out of memory");
|
||||
return (-1);
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
|
||||
wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size];
|
||||
wavebuf[i].dwBufferLength = spec->size;
|
||||
wavebuf[i].dwFlags = WHDR_DONE;
|
||||
result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
|
||||
SDL_memset(&this->hidden->wavebuf[i], '\0',
|
||||
sizeof (this->hidden->wavebuf[i]));
|
||||
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
|
||||
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
|
||||
this->hidden->wavebuf[i].lpData =
|
||||
(LPSTR) &this->hidden->mixbuf[i * this->spec.size];
|
||||
result = waveOutPrepareHeader(this->hidden->sound,
|
||||
&this->hidden->wavebuf[i],
|
||||
sizeof (this->hidden->wavebuf[i]));
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
WINWAVEOUT_CloseDevice(this);
|
||||
SetMMerror("waveOutPrepareHeader()", result);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ready to go! */
|
||||
next_buffer = 0;
|
||||
return (0);
|
||||
return 1; /* Ready to go! */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
WINWAVEOUT_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = WINWAVEOUT_OpenDevice;
|
||||
impl->ThreadInit = WINWAVEOUT_ThreadInit;
|
||||
impl->PlayDevice = WINWAVEOUT_PlayDevice;
|
||||
impl->WaitDevice = WINWAVEOUT_WaitDevice;
|
||||
impl->WaitDone = WINWAVEOUT_WaitDone;
|
||||
impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf;
|
||||
impl->CloseDevice = WINWAVEOUT_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap WINWAVEOUT_bootstrap = {
|
||||
"waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_dibaudio_h
|
||||
#define _SDL_dibaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
||||
@@ -40,12 +40,6 @@ struct SDL_PrivateAudioData
|
||||
int next_buffer;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define sound (this->hidden->sound)
|
||||
#define audio_sem (this->hidden->audio_sem)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define wavebuf (this->hidden->wavebuf)
|
||||
#define next_buffer (this->hidden->next_buffer)
|
||||
#endif /* _SDL_dibaudio_h */
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -28,160 +28,65 @@
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_dx5audio.h"
|
||||
|
||||
/* Define this if you want to use DirectX 6 DirectSoundNotify interface */
|
||||
//#define USE_POSITION_NOTIFY
|
||||
/* !!! FIXME: move this somewhere that other drivers can use it... */
|
||||
#if defined(_WIN32_WCE)
|
||||
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
|
||||
#elif defined(WIN64)
|
||||
#define WINDOWS_OS_NAME "Win64"
|
||||
#else
|
||||
#define WINDOWS_OS_NAME "Win32"
|
||||
#endif
|
||||
|
||||
/* DirectX function pointers for audio */
|
||||
HRESULT(WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
|
||||
|
||||
/* Audio driver functions */
|
||||
static int DX5_OpenAudio(_THIS, SDL_AudioSpec * spec);
|
||||
static void DX5_ThreadInit(_THIS);
|
||||
static void DX5_WaitAudio_BusyWait(_THIS);
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
static void DX6_WaitAudio_EventWait(_THIS);
|
||||
#endif
|
||||
static void DX5_PlayAudio(_THIS);
|
||||
static Uint8 *DX5_GetAudioBuf(_THIS);
|
||||
static void DX5_WaitDone(_THIS);
|
||||
static void DX5_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Audio_Available(void)
|
||||
{
|
||||
HINSTANCE DSoundDLL;
|
||||
int dsound_ok;
|
||||
|
||||
/* Version check DSOUND.DLL (Is DirectX okay?) */
|
||||
dsound_ok = 0;
|
||||
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
|
||||
if (DSoundDLL != NULL) {
|
||||
/* We just use basic DirectSound, we're okay */
|
||||
/* Yay! */
|
||||
/* Unfortunately, the sound drivers on NT have
|
||||
higher latencies than the audio buffers used
|
||||
by many SDL applications, so there are gaps
|
||||
in the audio - it sounds terrible. Punt for now.
|
||||
*/
|
||||
OSVERSIONINFO ver;
|
||||
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&ver);
|
||||
switch (ver.dwPlatformId) {
|
||||
case VER_PLATFORM_WIN32_NT:
|
||||
if (ver.dwMajorVersion > 4) {
|
||||
/* Win2K */
|
||||
dsound_ok = 1;
|
||||
} else {
|
||||
/* WinNT */
|
||||
dsound_ok = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Win95 or Win98 */
|
||||
dsound_ok = 1;
|
||||
break;
|
||||
}
|
||||
/* Now check for DirectX 5 or better - otherwise
|
||||
* we will fail later in DX5_OpenAudio without a chance
|
||||
* to fall back to the DIB driver. */
|
||||
if (dsound_ok) {
|
||||
/* DirectSoundCaptureCreate was added in DX5 */
|
||||
if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate")))
|
||||
dsound_ok = 0;
|
||||
|
||||
}
|
||||
/* Clean up.. */
|
||||
FreeLibrary(DSoundDLL);
|
||||
}
|
||||
return (dsound_ok);
|
||||
}
|
||||
|
||||
/* Functions for loading the DirectX functions dynamically */
|
||||
static HINSTANCE DSoundDLL = NULL;
|
||||
static HRESULT (WINAPI *DSoundCreate)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN) = NULL;
|
||||
|
||||
static void
|
||||
DX5_Unload(void)
|
||||
DSOUND_Unload(void)
|
||||
{
|
||||
if (DSoundDLL != NULL) {
|
||||
FreeLibrary(DSoundDLL);
|
||||
DSoundCreate = NULL;
|
||||
DSoundDLL = NULL;
|
||||
}
|
||||
|
||||
DSoundCreate = NULL;
|
||||
DSoundDLL = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
DX5_Load(void)
|
||||
DSOUND_Load(void)
|
||||
{
|
||||
int status;
|
||||
int loaded = 0;
|
||||
|
||||
DSOUND_Unload();
|
||||
|
||||
DX5_Unload();
|
||||
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
|
||||
if (DSoundDLL != NULL) {
|
||||
DSoundCreate = (void *) GetProcAddress(DSoundDLL,
|
||||
TEXT("DirectSoundCreate"));
|
||||
}
|
||||
if (DSoundDLL && DSoundCreate) {
|
||||
status = 0;
|
||||
if (DSoundDLL == NULL) {
|
||||
SDL_SetError("DirectSound: failed to load DSOUND.DLL");
|
||||
} 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 *
|
||||
Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Load DirectX */
|
||||
if (DX5_Load() < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* Now make sure we have DirectX 5 or better... */
|
||||
/* (DirectSoundCaptureCreate was added in DX5) */
|
||||
if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) {
|
||||
SDL_SetError("DirectSound: System doesn't appear to have DX5.");
|
||||
} else {
|
||||
DSoundCreate = (void *) GetProcAddress(DSoundDLL,
|
||||
TEXT("DirectSoundCreate"));
|
||||
}
|
||||
|
||||
if (!DSoundCreate) {
|
||||
SDL_SetError("DirectSound: Failed to find DirectSoundCreate");
|
||||
} else {
|
||||
loaded = 1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = DX5_OpenAudio;
|
||||
this->ThreadInit = DX5_ThreadInit;
|
||||
this->WaitAudio = DX5_WaitAudio_BusyWait;
|
||||
this->PlayAudio = DX5_PlayAudio;
|
||||
this->GetAudioBuf = DX5_GetAudioBuf;
|
||||
this->WaitDone = DX5_WaitDone;
|
||||
this->CloseAudio = DX5_CloseAudio;
|
||||
if (!loaded) {
|
||||
DSOUND_Unload();
|
||||
}
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
AudioBootStrap DSOUND_bootstrap = {
|
||||
"dsound", "Win95/98/2000 DirectSound",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
static void
|
||||
SetDSerror(const char *function, int code)
|
||||
@@ -192,8 +97,7 @@ SetDSerror(const char *function, int code)
|
||||
errbuf[0] = 0;
|
||||
switch (code) {
|
||||
case E_NOINTERFACE:
|
||||
error =
|
||||
"Unsupported interface\n-- Is DirectX 5.0 or later installed?";
|
||||
error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
|
||||
break;
|
||||
case DSERR_ALLOCATED:
|
||||
error = "Audio device in use";
|
||||
@@ -241,32 +145,36 @@ SetDSerror(const char *function, int code)
|
||||
/* DirectSound needs to be associated with a window */
|
||||
static HWND mainwin = NULL;
|
||||
/* */
|
||||
|
||||
void
|
||||
DX5_SoundFocus(HWND hwnd)
|
||||
DSOUND_SoundFocus(HWND hwnd)
|
||||
{
|
||||
/* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
|
||||
mainwin = hwnd;
|
||||
}
|
||||
|
||||
static void
|
||||
DX5_ThreadInit(_THIS)
|
||||
DSOUND_ThreadInit(_THIS)
|
||||
{
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
|
||||
static void
|
||||
DX5_WaitAudio_BusyWait(_THIS)
|
||||
DSOUND_WaitDevice(_THIS)
|
||||
{
|
||||
DWORD status;
|
||||
DWORD cursor, junk;
|
||||
HRESULT result;
|
||||
DWORD status = 0;
|
||||
DWORD cursor = 0;
|
||||
DWORD junk = 0;
|
||||
HRESULT result = DS_OK;
|
||||
|
||||
/* Semi-busy wait, since we have no way of getting play notification
|
||||
on a primary mixing buffer located in hardware (DirectX 5.0)
|
||||
*/
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
||||
&junk, &cursor);
|
||||
if (result != DS_OK) {
|
||||
if (result == DSERR_BUFFERLOST) {
|
||||
IDirectSoundBuffer_Restore(mixbuf);
|
||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
||||
}
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||
@@ -274,21 +182,22 @@ DX5_WaitAudio_BusyWait(_THIS)
|
||||
return;
|
||||
}
|
||||
|
||||
while ((cursor / mixlen) == lastchunk) {
|
||||
while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
|
||||
/* FIXME: find out how much time is left and sleep that long */
|
||||
SDL_Delay(1);
|
||||
|
||||
/* Try to restore a lost sound buffer */
|
||||
IDirectSoundBuffer_GetStatus(mixbuf, &status);
|
||||
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
|
||||
if ((status & DSBSTATUS_BUFFERLOST)) {
|
||||
IDirectSoundBuffer_Restore(mixbuf);
|
||||
IDirectSoundBuffer_GetStatus(mixbuf, &status);
|
||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
||||
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
|
||||
if ((status & DSBSTATUS_BUFFERLOST)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
|
||||
result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
|
||||
DSBPLAY_LOOPING);
|
||||
if (result == DS_OK) {
|
||||
continue;
|
||||
}
|
||||
@@ -299,7 +208,7 @@ DX5_WaitAudio_BusyWait(_THIS)
|
||||
}
|
||||
|
||||
/* Find out where we are playing */
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
||||
&junk, &cursor);
|
||||
if (result != DS_OK) {
|
||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||
@@ -308,222 +217,122 @@ DX5_WaitAudio_BusyWait(_THIS)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
static void
|
||||
DX6_WaitAudio_EventWait(_THIS)
|
||||
{
|
||||
DWORD status;
|
||||
HRESULT result;
|
||||
|
||||
/* Try to restore a lost sound buffer */
|
||||
IDirectSoundBuffer_GetStatus(mixbuf, &status);
|
||||
if ((status & DSBSTATUS_BUFFERLOST)) {
|
||||
IDirectSoundBuffer_Restore(mixbuf);
|
||||
IDirectSoundBuffer_GetStatus(mixbuf, &status);
|
||||
if ((status & DSBSTATUS_BUFFERLOST)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound Play", result);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
WaitForSingleObject(audio_event, INFINITE);
|
||||
}
|
||||
#endif /* USE_POSITION_NOTIFY */
|
||||
|
||||
static void
|
||||
DX5_PlayAudio(_THIS)
|
||||
DSOUND_PlayDevice(_THIS)
|
||||
{
|
||||
/* Unlock the buffer, allowing it to play */
|
||||
if (locked_buf) {
|
||||
IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
|
||||
if (this->hidden->locked_buf) {
|
||||
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
|
||||
this->hidden->locked_buf,
|
||||
this->hidden->mixlen, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
DX5_GetAudioBuf(_THIS)
|
||||
DSOUND_GetDeviceBuf(_THIS)
|
||||
{
|
||||
DWORD cursor, junk;
|
||||
HRESULT result;
|
||||
DWORD rawlen;
|
||||
DWORD cursor = 0;
|
||||
DWORD junk = 0;
|
||||
HRESULT result = DS_OK;
|
||||
DWORD rawlen = 0;
|
||||
|
||||
/* Figure out which blocks to fill next */
|
||||
locked_buf = NULL;
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
|
||||
this->hidden->locked_buf = NULL;
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
||||
&junk, &cursor);
|
||||
if (result == DSERR_BUFFERLOST) {
|
||||
IDirectSoundBuffer_Restore(mixbuf);
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
|
||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
||||
&junk, &cursor);
|
||||
}
|
||||
if (result != DS_OK) {
|
||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||
return (NULL);
|
||||
}
|
||||
cursor /= mixlen;
|
||||
cursor /= this->hidden->mixlen;
|
||||
#ifdef DEBUG_SOUND
|
||||
/* Detect audio dropouts */
|
||||
{
|
||||
DWORD spot = cursor;
|
||||
if (spot < lastchunk) {
|
||||
spot += NUM_BUFFERS;
|
||||
if (spot < this->hidden->lastchunk) {
|
||||
spot += this->hidden->num_buffers;
|
||||
}
|
||||
if (spot > lastchunk + 1) {
|
||||
if (spot > this->hidden->lastchunk + 1) {
|
||||
fprintf(stderr, "Audio dropout, missed %d fragments\n",
|
||||
(spot - (lastchunk + 1)));
|
||||
(spot - (this->hidden->lastchunk + 1)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
lastchunk = cursor;
|
||||
cursor = (cursor + 1) % NUM_BUFFERS;
|
||||
cursor *= mixlen;
|
||||
this->hidden->lastchunk = cursor;
|
||||
cursor = (cursor + 1) % this->hidden->num_buffers;
|
||||
cursor *= this->hidden->mixlen;
|
||||
|
||||
/* Lock the audio buffer */
|
||||
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
|
||||
(LPVOID *) & locked_buf, &rawlen, NULL,
|
||||
&junk, 0);
|
||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
||||
this->hidden->mixlen,
|
||||
(LPVOID *) &this->hidden->locked_buf,
|
||||
&rawlen, NULL, &junk, 0);
|
||||
if (result == DSERR_BUFFERLOST) {
|
||||
IDirectSoundBuffer_Restore(mixbuf);
|
||||
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
|
||||
(LPVOID *) & locked_buf, &rawlen,
|
||||
NULL, &junk, 0);
|
||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
||||
this->hidden->mixlen,
|
||||
(LPVOID *) &this->hidden->locked_buf,
|
||||
&rawlen, NULL, &junk, 0);
|
||||
}
|
||||
if (result != DS_OK) {
|
||||
SetDSerror("DirectSound Lock", result);
|
||||
return (NULL);
|
||||
}
|
||||
return (locked_buf);
|
||||
return (this->hidden->locked_buf);
|
||||
}
|
||||
|
||||
static void
|
||||
DX5_WaitDone(_THIS)
|
||||
DSOUND_WaitDone(_THIS)
|
||||
{
|
||||
Uint8 *stream;
|
||||
Uint8 *stream = DSOUND_GetDeviceBuf(this);
|
||||
|
||||
/* Wait for the playing chunk to finish */
|
||||
stream = this->GetAudioBuf(this);
|
||||
if (stream != NULL) {
|
||||
SDL_memset(stream, silence, mixlen);
|
||||
this->PlayAudio(this);
|
||||
SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
|
||||
DSOUND_PlayDevice(this);
|
||||
}
|
||||
this->WaitAudio(this);
|
||||
DSOUND_WaitDevice(this);
|
||||
|
||||
/* Stop the looping sound buffer */
|
||||
IDirectSoundBuffer_Stop(mixbuf);
|
||||
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
DX5_CloseAudio(_THIS)
|
||||
DSOUND_CloseDevice(_THIS)
|
||||
{
|
||||
if (sound != NULL) {
|
||||
if (mixbuf != NULL) {
|
||||
/* Clean up the audio buffer */
|
||||
IDirectSoundBuffer_Release(mixbuf);
|
||||
mixbuf = NULL;
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->sound != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
/* Clean up the audio buffer */
|
||||
IDirectSoundBuffer_Release(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
IDirectSound_Release(this->hidden->sound);
|
||||
this->hidden->sound = NULL;
|
||||
}
|
||||
if (audio_event != NULL) {
|
||||
CloseHandle(audio_event);
|
||||
audio_event = NULL;
|
||||
}
|
||||
IDirectSound_Release(sound);
|
||||
sound = NULL;
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PRIMARY_BUFFER
|
||||
/* This function tries to create a primary audio buffer, and returns the
|
||||
number of audio chunks available in the created buffer.
|
||||
*/
|
||||
static int
|
||||
CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
|
||||
Uint32 chunksize)
|
||||
{
|
||||
HRESULT result;
|
||||
DSBUFFERDESC format;
|
||||
DSBCAPS caps;
|
||||
int numchunks;
|
||||
|
||||
/* Try to set primary mixing privileges */
|
||||
result = IDirectSound_SetCooperativeLevel(sndObj, focus,
|
||||
DSSCL_WRITEPRIMARY);
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound SetCooperativeLevel", result);
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Try to create the primary buffer */
|
||||
SDL_memset(&format, 0, sizeof(format));
|
||||
format.dwSize = sizeof(format);
|
||||
format.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2);
|
||||
format.dwFlags |= DSBCAPS_STICKYFOCUS;
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
|
||||
#endif
|
||||
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound CreateSoundBuffer", result);
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Check the size of the fragment buffer */
|
||||
SDL_memset(&caps, 0, sizeof(caps));
|
||||
caps.dwSize = sizeof(caps);
|
||||
result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound GetCaps", result);
|
||||
#endif
|
||||
IDirectSoundBuffer_Release(*sndbuf);
|
||||
return (-1);
|
||||
}
|
||||
if ((chunksize > caps.dwBufferBytes) ||
|
||||
((caps.dwBufferBytes % chunksize) != 0)) {
|
||||
/* The primary buffer size is not a multiple of 'chunksize'
|
||||
-- this hopefully doesn't happen when 'chunksize' is a
|
||||
power of 2.
|
||||
*/
|
||||
IDirectSoundBuffer_Release(*sndbuf);
|
||||
SDL_SetError
|
||||
("Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
|
||||
caps.dwBufferBytes, chunksize);
|
||||
return (-1);
|
||||
}
|
||||
numchunks = (caps.dwBufferBytes / chunksize);
|
||||
|
||||
/* Set the primary audio format */
|
||||
result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound SetFormat", result);
|
||||
#endif
|
||||
IDirectSoundBuffer_Release(*sndbuf);
|
||||
return (-1);
|
||||
}
|
||||
return (numchunks);
|
||||
}
|
||||
#endif /* USE_PRIMARY_BUFFER */
|
||||
|
||||
/* This function tries to create a secondary audio buffer, and returns the
|
||||
number of audio chunks available in the created buffer.
|
||||
*/
|
||||
static int
|
||||
CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
|
||||
Uint32 chunksize)
|
||||
CreateSecondary(_THIS, HWND focus, WAVEFORMATEX *wavefmt)
|
||||
{
|
||||
LPDIRECTSOUND sndObj = this->hidden->sound;
|
||||
LPDIRECTSOUNDBUFFER *sndbuf = this->hidden->mixbuf;
|
||||
Uint32 chunksize = this->spec.size;
|
||||
const int numchunks = 8;
|
||||
HRESULT result;
|
||||
HRESULT result = DS_OK;
|
||||
DSBUFFERDESC format;
|
||||
LPVOID pvAudioPtr1, pvAudioPtr2;
|
||||
DWORD dwAudioBytes1, dwAudioBytes2;
|
||||
@@ -538,9 +347,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
DSSCL_NORMAL);
|
||||
}
|
||||
if (result != DS_OK) {
|
||||
#ifdef DEBUG_SOUND
|
||||
SetDSerror("DirectSound SetCooperativeLevel", result);
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -548,9 +355,6 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
SDL_memset(&format, 0, sizeof(format));
|
||||
format.dwSize = sizeof(format);
|
||||
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
|
||||
#endif
|
||||
if (!focus) {
|
||||
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
||||
} else {
|
||||
@@ -578,11 +382,7 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
(LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
|
||||
DSBLOCK_ENTIREBUFFER);
|
||||
if (result == DS_OK) {
|
||||
if (wavefmt->wBitsPerSample == 8) {
|
||||
SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
|
||||
} else {
|
||||
SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
|
||||
}
|
||||
SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
|
||||
IDirectSoundBuffer_Unlock(*sndbuf,
|
||||
(LPVOID) pvAudioPtr1, dwAudioBytes1,
|
||||
(LPVOID) pvAudioPtr2, dwAudioBytes2);
|
||||
@@ -592,148 +392,125 @@ CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
|
||||
return (numchunks);
|
||||
}
|
||||
|
||||
/* This function tries to set position notify events on the mixing buffer */
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
static int
|
||||
CreateAudioEvent(_THIS)
|
||||
{
|
||||
LPDIRECTSOUNDNOTIFY notify;
|
||||
DSBPOSITIONNOTIFY *notify_positions;
|
||||
int i, retval;
|
||||
HRESULT result;
|
||||
|
||||
/* Default to fail on exit */
|
||||
retval = -1;
|
||||
notify = NULL;
|
||||
|
||||
/* Query for the interface */
|
||||
result = IDirectSoundBuffer_QueryInterface(mixbuf,
|
||||
&IID_IDirectSoundNotify,
|
||||
(void *) ¬ify);
|
||||
if (result != DS_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Allocate the notify structures */
|
||||
notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc(NUM_BUFFERS *
|
||||
sizeof
|
||||
(*notify_positions));
|
||||
if (notify_positions == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Create the notify event */
|
||||
audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (audio_event == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set up the notify structures */
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
notify_positions[i].dwOffset = i * mixlen;
|
||||
notify_positions[i].hEventNotify = audio_event;
|
||||
}
|
||||
result = IDirectSoundNotify_SetNotificationPositions(notify,
|
||||
NUM_BUFFERS,
|
||||
notify_positions);
|
||||
if (result == DS_OK) {
|
||||
retval = 0;
|
||||
}
|
||||
done:
|
||||
if (notify != NULL) {
|
||||
IDirectSoundNotify_Release(notify);
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
#endif /* USE_POSITION_NOTIFY */
|
||||
|
||||
static int
|
||||
DX5_OpenAudio(_THIS, SDL_AudioSpec * spec)
|
||||
DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
HRESULT result;
|
||||
WAVEFORMATEX waveformat;
|
||||
int valid_format = 0;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
|
||||
/* !!! FIXME: handle devname */
|
||||
/* !!! FIXME: handle iscapture */
|
||||
|
||||
/* 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));
|
||||
|
||||
while ((!valid_format) && (test_format)) {
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S16:
|
||||
case AUDIO_S32:
|
||||
this->spec.format = test_format;
|
||||
valid_format = 1;
|
||||
break;
|
||||
}
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
DSOUND_CloseDevice(this);
|
||||
SDL_SetError("DirectSound: Unsupported audio format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set basic WAVE format parameters */
|
||||
SDL_memset(&waveformat, 0, sizeof(waveformat));
|
||||
waveformat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
|
||||
/* Determine the audio parameters from the AudioSpec */
|
||||
switch (SDL_AUDIO_BITSIZE(spec->format)) {
|
||||
case 8:
|
||||
/* Unsigned 8 bit audio data */
|
||||
spec->format = AUDIO_U8;
|
||||
silence = 0x80;
|
||||
waveformat.wBitsPerSample = 8;
|
||||
break;
|
||||
case 16:
|
||||
/* Signed 16 bit audio data */
|
||||
spec->format = AUDIO_S16;
|
||||
silence = 0x00;
|
||||
waveformat.wBitsPerSample = 16;
|
||||
break;
|
||||
case 32:
|
||||
/* Signed 32 bit audio data */
|
||||
spec->format = AUDIO_S32;
|
||||
silence = 0x00;
|
||||
waveformat.wBitsPerSample = 32;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unsupported audio format");
|
||||
return (-1);
|
||||
}
|
||||
waveformat.nChannels = spec->channels;
|
||||
waveformat.nSamplesPerSec = spec->freq;
|
||||
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
waveformat.nChannels = this->spec.channels;
|
||||
waveformat.nSamplesPerSec = this->spec.freq;
|
||||
waveformat.nBlockAlign =
|
||||
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
|
||||
waveformat.nAvgBytesPerSec =
|
||||
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Open the audio device */
|
||||
result = DSoundCreate(NULL, &sound, NULL);
|
||||
result = DSoundCreate(NULL, &this->hidden->sound, NULL);
|
||||
if (result != DS_OK) {
|
||||
DSOUND_CloseDevice(this);
|
||||
SetDSerror("DirectSoundCreate", result);
|
||||
return (-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the audio buffer to which we write */
|
||||
NUM_BUFFERS = -1;
|
||||
#ifdef USE_PRIMARY_BUFFER
|
||||
if (mainwin) {
|
||||
NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
|
||||
&waveformat, spec->size);
|
||||
this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
|
||||
if (this->hidden->num_buffers < 0) {
|
||||
DSOUND_CloseDevice(this);
|
||||
return 0;
|
||||
}
|
||||
#endif /* USE_PRIMARY_BUFFER */
|
||||
if (NUM_BUFFERS < 0) {
|
||||
NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
|
||||
&waveformat, spec->size);
|
||||
if (NUM_BUFFERS < 0) {
|
||||
return (-1);
|
||||
}
|
||||
#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;
|
||||
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
|
||||
#ifdef USE_POSITION_NOTIFY
|
||||
/* See if we can use DirectX 6 event notification */
|
||||
if (CreateAudioEvent(this) == 0) {
|
||||
this->WaitAudio = DX6_WaitAudio_EventWait;
|
||||
} else {
|
||||
this->WaitAudio = DX5_WaitAudio_BusyWait;
|
||||
}
|
||||
#endif
|
||||
return (0);
|
||||
return 1; /* good to go. */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DSOUND_Deinitialize(void)
|
||||
{
|
||||
DSOUND_Unload();
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
DSOUND_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
OSVERSIONINFO ver;
|
||||
|
||||
/*
|
||||
* Unfortunately, the sound drivers on NT have higher latencies than the
|
||||
* audio buffers used by many SDL applications, so there are gaps in the
|
||||
* audio - it sounds terrible. Punt for now.
|
||||
*/
|
||||
SDL_memset(&ver, '\0', sizeof (OSVERSIONINFO));
|
||||
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&ver);
|
||||
if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
if (ver.dwMajorVersion <= 4) {
|
||||
return 0; /* NT4.0 or earlier. Disable dsound support. */
|
||||
}
|
||||
}
|
||||
|
||||
if (!DSOUND_Load()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = DSOUND_OpenDevice;
|
||||
impl->PlayDevice = DSOUND_PlayDevice;
|
||||
impl->WaitDevice = DSOUND_WaitDevice;
|
||||
impl->WaitDone = DSOUND_WaitDone;
|
||||
impl->ThreadInit = DSOUND_ThreadInit;
|
||||
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
|
||||
impl->CloseDevice = DSOUND_CloseDevice;
|
||||
impl->Deinitialize = DSOUND_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioBootStrap DSOUND_bootstrap = {
|
||||
"dsound", WINDOWS_OS_NAME "DirectSound", DSOUND_Init, 0
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifndef _SDL_lowaudio_h
|
||||
#define _SDL_lowaudio_h
|
||||
#ifndef _SDL_dx5audio_h
|
||||
#define _SDL_dx5audio_h
|
||||
|
||||
#include "directx.h"
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
/* The DirectSound objects */
|
||||
@@ -36,23 +36,12 @@ struct SDL_PrivateAudioData
|
||||
{
|
||||
LPDIRECTSOUND sound;
|
||||
LPDIRECTSOUNDBUFFER mixbuf;
|
||||
int NUM_BUFFERS;
|
||||
int mixlen, silence;
|
||||
int num_buffers;
|
||||
int mixlen;
|
||||
DWORD lastchunk;
|
||||
Uint8 *locked_buf;
|
||||
HANDLE audio_event;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define sound (this->hidden->sound)
|
||||
#define mixbuf (this->hidden->mixbuf)
|
||||
#define NUM_BUFFERS (this->hidden->NUM_BUFFERS)
|
||||
#define mixlen (this->hidden->mixlen)
|
||||
#define silence (this->hidden->silence)
|
||||
#define lastchunk (this->hidden->lastchunk)
|
||||
#define locked_buf (this->hidden->locked_buf)
|
||||
#define audio_event (this->hidden->audio_event)
|
||||
|
||||
#endif /* _SDL_lowaudio_h */
|
||||
#endif /* _SDL_dx5audio_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -165,7 +165,7 @@ SDL_GetMouseFocusWindow()
|
||||
return mouse->focus;
|
||||
}
|
||||
|
||||
static int
|
||||
static int SDLCALL
|
||||
FlushMouseMotion(void *param, SDL_Event * event)
|
||||
{
|
||||
if (event->type == SDL_MOUSEMOTION
|
||||
|
||||
@@ -65,24 +65,28 @@ SDL_GetTicks(void)
|
||||
*/
|
||||
/* inline asm to avoid runtime inclusion */
|
||||
_asm {
|
||||
push edx
|
||||
push eax
|
||||
mov eax, dword ptr hires_now
|
||||
mov edx, dword ptr hires_now + 4
|
||||
sub eax, dword ptr hires_start_ticks
|
||||
sbb edx, dword ptr hires_start_ticks + 4
|
||||
mov ebx, 1000
|
||||
mov ecx, edx
|
||||
mul ebx
|
||||
push eax
|
||||
push edx
|
||||
mov eax, ecx
|
||||
mul ebx
|
||||
pop eax
|
||||
add edx, eax
|
||||
pop eax
|
||||
mov ebx, dword ptr hires_ticks_per_second
|
||||
div ebx mov dword ptr ticks, eax pop edx pop eax}
|
||||
push edx
|
||||
push eax
|
||||
mov eax, dword ptr hires_now
|
||||
mov edx, dword ptr hires_now + 4
|
||||
sub eax, dword ptr hires_start_ticks
|
||||
sbb edx, dword ptr hires_start_ticks + 4
|
||||
mov ebx, 1000
|
||||
mov ecx, edx
|
||||
mul ebx
|
||||
push eax
|
||||
push edx
|
||||
mov eax, ecx
|
||||
mul ebx
|
||||
pop eax
|
||||
add edx, eax
|
||||
pop eax
|
||||
mov ebx, dword ptr hires_ticks_per_second
|
||||
div ebx
|
||||
mov dword ptr ticks, eax
|
||||
pop edx
|
||||
pop eax
|
||||
}
|
||||
|
||||
return ticks;
|
||||
|
||||
@@ -178,7 +182,7 @@ SDL_Delay(Uint32 ms)
|
||||
static int timer_alive = 0;
|
||||
static SDL_Thread *timer = NULL;
|
||||
|
||||
static int
|
||||
static int SDLCALL
|
||||
RunTimer(void *unused)
|
||||
{
|
||||
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
#define SDL_RENDERCOPY_NEAREST 0x0100
|
||||
|
||||
typedef struct {
|
||||
void *src;
|
||||
Uint8 *src;
|
||||
int src_w, src_h;
|
||||
int src_pitch;
|
||||
void *dst;
|
||||
Uint8 *dst;
|
||||
int dst_w, dst_h;
|
||||
int dst_pitch;
|
||||
void *aux_data;
|
||||
@@ -44,7 +44,7 @@ typedef struct {
|
||||
Uint8 r, g, b, a;
|
||||
} SDL_RenderCopyData;
|
||||
|
||||
typedef int (*SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
|
||||
typedef int (SDLCALL * SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
|
||||
|
||||
extern SDL_RenderCopyFunc SDLCALL SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ EXE = @EXE@
|
||||
CFLAGS = @CFLAGS@
|
||||
LIBS = @LIBS@
|
||||
|
||||
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE)
|
||||
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE)
|
||||
|
||||
all: Makefile $(TARGETS)
|
||||
|
||||
@@ -23,6 +23,12 @@ graywin$(EXE): $(srcdir)/graywin.c
|
||||
loopwave$(EXE): $(srcdir)/loopwave.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testaudioinfo$(EXE): $(srcdir)/testaudioinfo.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testalpha$(EXE): $(srcdir)/testalpha.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@
|
||||
|
||||
|
||||
@@ -69,26 +69,12 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* Print available audio drivers */
|
||||
n = SDL_GetNumAudioDrivers();
|
||||
if (n == 0) {
|
||||
printf("No built-in audio drivers\n");
|
||||
} else {
|
||||
printf("Built-in audio drivers:");
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
printf(",");
|
||||
}
|
||||
printf(" %s", SDL_GetAudioDriver(i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Load the SDL library */
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (argv[1] == NULL) {
|
||||
argv[1] = "sample.wav";
|
||||
}
|
||||
@@ -120,7 +106,6 @@ main(int argc, char *argv[])
|
||||
SDL_PauseAudio(0);
|
||||
|
||||
/* Let the audio run */
|
||||
printf("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
|
||||
while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING))
|
||||
SDL_Delay(1000);
|
||||
|
||||
|
||||
53
test/testaudioinfo.c
Normal file
53
test/testaudioinfo.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
136
test/testmultiaudio.c
Normal file
136
test/testmultiaudio.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user