aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-01-26 07:06:02 +0100
committerSven Gothel <[email protected]>2014-01-26 07:06:02 +0100
commite6f4251945c228a775649b5ccd7f11dd4519c28d (patch)
tree8454b34363358cf9bb502021a68c6985c97daac4
parent389ae1f767bfad6116e21306fc3cdf89a4cbcc0a (diff)
parent49baa9128dd98e986639def4f24c7522d9ec6b56 (diff)
Merge branch 'UPSTREAM'
-rw-r--r--.gitignore1
-rw-r--r--Alc/ALc.c589
-rw-r--r--Alc/ALu.c251
-rw-r--r--Alc/alcConfig.c305
-rw-r--r--Alc/alcDedicated.c100
-rw-r--r--Alc/alcEcho.c184
-rw-r--r--Alc/alcModulator.c204
-rw-r--r--Alc/alcRing.c1
-rw-r--r--Alc/alcThread.c144
-rw-r--r--Alc/atomic.h180
-rw-r--r--Alc/backends/alsa.c893
-rw-r--r--Alc/backends/base.c230
-rw-r--r--Alc/backends/base.h133
-rw-r--r--Alc/backends/coreaudio.c2
-rw-r--r--Alc/backends/dsound.c37
-rw-r--r--Alc/backends/loopback.c116
-rw-r--r--Alc/backends/mmdevapi.c15
-rw-r--r--Alc/backends/null.c184
-rw-r--r--Alc/backends/opensl.c40
-rw-r--r--Alc/backends/oss.c457
-rw-r--r--Alc/backends/portaudio.c28
-rw-r--r--Alc/backends/pulseaudio.c1516
-rw-r--r--Alc/backends/qsa.c1169
-rw-r--r--Alc/backends/sndio.c9
-rw-r--r--Alc/backends/solaris.c13
-rw-r--r--Alc/backends/wave.c16
-rw-r--r--Alc/backends/winmm.c17
-rw-r--r--Alc/compat.h65
-rw-r--r--Alc/effects/autowah.c275
-rw-r--r--Alc/effects/chorus.c381
-rw-r--r--Alc/effects/compressor.c223
-rw-r--r--Alc/effects/dedicated.c167
-rw-r--r--Alc/effects/distortion.c300
-rw-r--r--Alc/effects/echo.c296
-rw-r--r--Alc/effects/equalizer.c337
-rw-r--r--Alc/effects/flanger.c380
-rw-r--r--Alc/effects/modulator.c306
-rw-r--r--Alc/effects/null.c155
-rw-r--r--Alc/effects/reverb.c (renamed from Alc/alcReverb.c)931
-rw-r--r--Alc/evtqueue.h31
-rw-r--r--Alc/helpers.c130
-rw-r--r--Alc/hrtf.c26
-rw-r--r--Alc/midi/base.c278
-rw-r--r--Alc/midi/base.h128
-rw-r--r--Alc/midi/dummy.c95
-rw-r--r--Alc/midi/fluidsynth.c843
-rw-r--r--Alc/midi/sf2load.c1436
-rw-r--r--Alc/mixer.c22
-rw-r--r--Alc/mixer_c.c66
-rw-r--r--Alc/mixer_defs.h22
-rw-r--r--Alc/mixer_inc.c43
-rw-r--r--Alc/mixer_neon.c19
-rw-r--r--Alc/mixer_sse.c120
-rw-r--r--Alc/panning.c108
-rw-r--r--Alc/rwlock.h21
-rw-r--r--Alc/threads.c200
-rw-r--r--Alc/uintmap.h34
-rw-r--r--CMakeLists.txt332
-rw-r--r--OpenAL32/Include/alAuxEffectSlot.h88
-rw-r--r--OpenAL32/Include/alBuffer.h14
-rw-r--r--OpenAL32/Include/alEffect.h127
-rw-r--r--OpenAL32/Include/alError.h15
-rw-r--r--OpenAL32/Include/alFilter.h78
-rw-r--r--OpenAL32/Include/alMain.h759
-rw-r--r--OpenAL32/Include/alMidi.h166
-rw-r--r--OpenAL32/Include/alSource.h31
-rw-r--r--OpenAL32/Include/alu.h76
-rw-r--r--OpenAL32/Include/threads.h14
-rw-r--r--OpenAL32/alAuxEffectSlot.c625
-rw-r--r--OpenAL32/alBuffer.c1398
-rw-r--r--OpenAL32/alEffect.c1232
-rw-r--r--OpenAL32/alError.c5
-rw-r--r--OpenAL32/alExtension.c62
-rw-r--r--OpenAL32/alFilter.c296
-rw-r--r--OpenAL32/alFontsound.c972
-rw-r--r--OpenAL32/alListener.c562
-rw-r--r--OpenAL32/alMidi.c221
-rw-r--r--OpenAL32/alPreset.c340
-rw-r--r--OpenAL32/alSoundfont.c563
-rw-r--r--OpenAL32/alSource.c885
-rw-r--r--OpenAL32/alState.c796
-rw-r--r--alsoftrc.sample73
-rw-r--r--cmake/CheckCCompilerFlag.cmake59
-rw-r--r--cmake/FindFluidSynth.cmake23
-rw-r--r--cmake/FindSDL_sound.cmake382
-rw-r--r--config.h.in33
-rw-r--r--examples/allatency.c59
-rw-r--r--examples/alloopback.c244
-rw-r--r--examples/alreverb.c76
-rw-r--r--examples/alstream.c80
-rw-r--r--examples/common/alffmpeg.c638
-rw-r--r--examples/common/alffmpeg.h66
-rw-r--r--examples/common/alhelpers.h4
-rw-r--r--examples/common/sdl_sound.c164
-rw-r--r--examples/common/sdl_sound.h43
-rw-r--r--include/AL/alext.h16
-rw-r--r--utils/CIAIR.def2
-rw-r--r--utils/IRC_1005.def6
-rw-r--r--utils/MIT_KEMAR.def20
-rw-r--r--utils/alsoft-config/CMakeLists.txt29
-rw-r--r--utils/alsoft-config/main.cpp11
-rw-r--r--utils/alsoft-config/mainwindow.cpp586
-rw-r--r--utils/alsoft-config/mainwindow.h56
-rw-r--r--utils/alsoft-config/mainwindow.ui1397
-rw-r--r--utils/makehrtf.c113
105 files changed, 20368 insertions, 7741 deletions
diff --git a/.gitignore b/.gitignore
index cfa0c201..b792eb2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
build
winbuild
+win64build
include/sndio.h
include/sys
openal-soft.kdev4
diff --git a/Alc/ALc.c b/Alc/ALc.c
index fd5b8894..fea0320d 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -35,64 +35,78 @@
#include "alBuffer.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
+#include "alMidi.h"
#include "bs2b.h"
#include "alu.h"
+#include "backends/base.h"
+#include "midi/base.h"
+
/************************************************
* Backends
************************************************/
-#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+struct BackendInfo {
+ const char *name;
+ ALCbackendFactory* (*getFactory)(void);
+ ALCboolean (*Init)(BackendFuncs*);
+ void (*Deinit)(void);
+ void (*Probe)(enum DevProbe);
+ BackendFuncs Funcs;
+};
+
+#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
static struct BackendInfo BackendList[] = {
#ifdef HAVE_PULSEAUDIO
- { "pulse", alc_pulse_init, alc_pulse_deinit, alc_pulse_probe, EmptyFuncs },
+ { "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_ALSA
- { "alsa", alc_alsa_init, alc_alsa_deinit, alc_alsa_probe, EmptyFuncs },
+ { "alsa", ALCalsaBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_COREAUDIO
- { "core", alc_ca_init, alc_ca_deinit, alc_ca_probe, EmptyFuncs },
+ { "core", NULL, alc_ca_init, alc_ca_deinit, alc_ca_probe, EmptyFuncs },
#endif
#ifdef HAVE_OSS
- { "oss", alc_oss_init, alc_oss_deinit, alc_oss_probe, EmptyFuncs },
+ { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_SOLARIS
- { "solaris", alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs },
+ { "solaris", NULL, alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs },
#endif
#ifdef HAVE_SNDIO
- { "sndio", alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs },
+ { "sndio", NULL, alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_QSA
+ { "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs },
#endif
#ifdef HAVE_MMDEVAPI
- { "mmdevapi", alcMMDevApiInit, alcMMDevApiDeinit, alcMMDevApiProbe, EmptyFuncs },
+ { "mmdevapi", NULL, alcMMDevApiInit, alcMMDevApiDeinit, alcMMDevApiProbe, EmptyFuncs },
#endif
#ifdef HAVE_DSOUND
- { "dsound", alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs },
+ { "dsound", NULL, alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs },
#endif
#ifdef HAVE_WINMM
- { "winmm", alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
+ { "winmm", NULL, alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
#endif
#ifdef HAVE_PORTAUDIO
- { "port", alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs },
+ { "port", NULL, alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs },
#endif
#ifdef HAVE_OPENSL
- { "opensl", alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs },
+ { "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs },
#endif
- { "null", alc_null_init, alc_null_deinit, alc_null_probe, EmptyFuncs },
+ { "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#ifdef HAVE_WAVE
- { "wave", alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs },
+ { "wave", NULL, alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs },
#endif
- { NULL, NULL, NULL, NULL, EmptyFuncs }
-};
-static struct BackendInfo BackendLoopback = {
- "loopback", alc_loopback_init, alc_loopback_deinit, alc_loopback_probe, EmptyFuncs
+ { NULL, NULL, NULL, NULL, NULL, EmptyFuncs }
};
#undef EmptyFuncs
static struct BackendInfo PlaybackBackend;
static struct BackendInfo CaptureBackend;
+
/************************************************
* Functions, enums, and errors
************************************************/
@@ -136,6 +150,9 @@ static const ALCfunction alcFunctions[] = {
DECL(alcIsRenderFormatSupportedSOFT),
DECL(alcRenderSamplesSOFT),
+ DECL(alcDevicePauseSOFT),
+ DECL(alcDeviceResumeSOFT),
+
DECL(alEnable),
DECL(alDisable),
DECL(alIsEnabled),
@@ -267,6 +284,44 @@ static const ALCfunction alcFunctions[] = {
DECL(alGetSource3i64SOFT),
DECL(alGetSourcei64vSOFT),
+ DECL(alGenSoundfontsSOFT),
+ DECL(alDeleteSoundfontsSOFT),
+ DECL(alIsSoundfontSOFT),
+ DECL(alSoundfontSamplesSOFT),
+ DECL(alGetSoundfontSamplesSOFT),
+ DECL(alSoundfontMapSamplesSOFT),
+ DECL(alSoundfontUnmapSamplesSOFT),
+ DECL(alGetSoundfontivSOFT),
+ DECL(alSoundfontPresetsSOFT),
+ DECL(alGenPresetsSOFT),
+ DECL(alDeletePresetsSOFT),
+ DECL(alIsPresetSOFT),
+ DECL(alPresetiSOFT),
+ DECL(alPresetivSOFT),
+ DECL(alGetPresetivSOFT),
+ DECL(alPresetFontsoundsSOFT),
+ DECL(alGenFontsoundsSOFT),
+ DECL(alDeleteFontsoundsSOFT),
+ DECL(alIsFontsoundSOFT),
+ DECL(alFontsoundiSOFT),
+ DECL(alFontsound2iSOFT),
+ DECL(alFontsoundivSOFT),
+ DECL(alGetFontsoundivSOFT),
+ DECL(alFontsoundModulatoriSOFT),
+ DECL(alGetFontsoundModulatorivSOFT),
+ DECL(alMidiSoundfontSOFT),
+ DECL(alMidiSoundfontvSOFT),
+ DECL(alMidiEventSOFT),
+ DECL(alMidiSysExSOFT),
+ DECL(alMidiPlaySOFT),
+ DECL(alMidiPauseSOFT),
+ DECL(alMidiStopSOFT),
+ DECL(alMidiResetSOFT),
+ DECL(alMidiGainSOFT),
+ DECL(alGetInteger64SOFT),
+ DECL(alGetInteger64vSOFT),
+ DECL(alLoadSoundfontSOFT),
+
{ NULL, NULL }
};
#undef DECL
@@ -512,23 +567,19 @@ static const ALCenums enumeration[] = {
DECL(AL_EFFECT_NULL),
DECL(AL_EFFECT_REVERB),
DECL(AL_EFFECT_EAXREVERB),
-#if 0
DECL(AL_EFFECT_CHORUS),
DECL(AL_EFFECT_DISTORTION),
-#endif
DECL(AL_EFFECT_ECHO),
-#if 0
DECL(AL_EFFECT_FLANGER),
+#if 0
DECL(AL_EFFECT_FREQUENCY_SHIFTER),
DECL(AL_EFFECT_VOCAL_MORPHER),
DECL(AL_EFFECT_PITCH_SHIFTER),
#endif
DECL(AL_EFFECT_RING_MODULATOR),
-#if 0
DECL(AL_EFFECT_AUTOWAH),
DECL(AL_EFFECT_COMPRESSOR),
DECL(AL_EFFECT_EQUALIZER),
-#endif
DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT),
DECL(AL_EFFECT_DEDICATED_DIALOGUE),
@@ -570,16 +621,54 @@ static const ALCenums enumeration[] = {
DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR),
DECL(AL_REVERB_DECAY_HFLIMIT),
+ DECL(AL_CHORUS_WAVEFORM),
+ DECL(AL_CHORUS_PHASE),
+ DECL(AL_CHORUS_RATE),
+ DECL(AL_CHORUS_DEPTH),
+ DECL(AL_CHORUS_FEEDBACK),
+ DECL(AL_CHORUS_DELAY),
+
+ DECL(AL_DISTORTION_EDGE),
+ DECL(AL_DISTORTION_GAIN),
+ DECL(AL_DISTORTION_LOWPASS_CUTOFF),
+ DECL(AL_DISTORTION_EQCENTER),
+ DECL(AL_DISTORTION_EQBANDWIDTH),
+
DECL(AL_ECHO_DELAY),
DECL(AL_ECHO_LRDELAY),
DECL(AL_ECHO_DAMPING),
DECL(AL_ECHO_FEEDBACK),
DECL(AL_ECHO_SPREAD),
+ DECL(AL_FLANGER_WAVEFORM),
+ DECL(AL_FLANGER_PHASE),
+ DECL(AL_FLANGER_RATE),
+ DECL(AL_FLANGER_DEPTH),
+ DECL(AL_FLANGER_FEEDBACK),
+ DECL(AL_FLANGER_DELAY),
+
DECL(AL_RING_MODULATOR_FREQUENCY),
DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF),
DECL(AL_RING_MODULATOR_WAVEFORM),
+ DECL(AL_AUTOWAH_ATTACK_TIME),
+ DECL(AL_AUTOWAH_PEAK_GAIN),
+ DECL(AL_AUTOWAH_RELEASE_TIME),
+ DECL(AL_AUTOWAH_RESONANCE),
+
+ DECL(AL_COMPRESSOR_ONOFF),
+
+ DECL(AL_EQUALIZER_LOW_GAIN),
+ DECL(AL_EQUALIZER_LOW_CUTOFF),
+ DECL(AL_EQUALIZER_MID1_GAIN),
+ DECL(AL_EQUALIZER_MID1_CENTER),
+ DECL(AL_EQUALIZER_MID1_WIDTH),
+ DECL(AL_EQUALIZER_MID2_GAIN),
+ DECL(AL_EQUALIZER_MID2_CENTER),
+ DECL(AL_EQUALIZER_MID2_WIDTH),
+ DECL(AL_EQUALIZER_HIGH_GAIN),
+ DECL(AL_EQUALIZER_HIGH_CUTOFF),
+
DECL(AL_DEDICATED_GAIN),
{ NULL, (ALCenum)0 }
@@ -616,13 +705,13 @@ static const ALchar alExtList[] =
"AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW "
"AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model "
"AL_LOKI_quadriphonic AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data "
- "AL_SOFTX_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points "
+ "AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points "
"AL_SOFT_source_latency";
static volatile ALCenum LastNullDeviceError = ALC_NO_ERROR;
/* Thread-local current context */
-static pthread_key_t LocalContext;
+static althread_key_t LocalContext;
/* Process-wide current context */
static ALCcontext *volatile GlobalContext = NULL;
@@ -640,7 +729,7 @@ enum LogLevel LogLevel = LogError;
static ALCboolean TrapALCError = ALC_FALSE;
/* One-time configuration init control */
-static pthread_once_t alc_config_once = PTHREAD_ONCE_INIT;
+static althread_once_t alc_config_once = ALTHREAD_ONCE_INIT;
/* Default effect that applies to sources that don't have an effect on send 0 */
static ALeffect DefaultEffect;
@@ -655,7 +744,8 @@ static const ALCchar alcNoDeviceExtList[] =
static const ALCchar alcExtensionList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX "
- "ALC_EXT_thread_local_context ALC_SOFT_loopback";
+ "ALC_EXT_thread_local_context ALC_SOFTX_HRTF ALC_SOFT_loopback "
+ "ALC_SOFTX_midi_interface ALC_SOFTX_pause_device";
static const ALCint alcMajorVersion = 1;
static const ALCint alcMinorVersion = 1;
@@ -709,7 +799,7 @@ BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserv
LockUIntMapRead(&TlsDestructor);
for(i = 0;i < TlsDestructor.size;i++)
{
- void *ptr = pthread_getspecific(TlsDestructor.array[i].key);
+ void *ptr = althread_getspecific(TlsDestructor.array[i].key);
void (*callback)(void*) = (void(*)(void*))TlsDestructor.array[i].value;
if(ptr && callback)
callback(ptr);
@@ -774,7 +864,7 @@ static void alc_init(void)
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
ZScale *= -1.0f;
- pthread_key_create(&LocalContext, ReleaseThreadCtx);
+ althread_key_create(&LocalContext, ReleaseThreadCtx);
InitializeCriticalSection(&ListLock);
ThunkInit();
}
@@ -797,7 +887,7 @@ static void alc_initconfig(void)
str = getenv("ALSOFT_LOGFILE");
if(str && str[0])
{
- FILE *logfile = fopen(str, "wat");
+ FILE *logfile = fopen(str, "wt");
if(logfile) LogFile = logfile;
else ERR("Failed to open log file '%s'\n", str);
}
@@ -813,7 +903,7 @@ static void alc_initconfig(void)
capfilter = 0;
#ifdef HAVE_SSE
- capfilter |= CPU_CAP_SSE;
+ capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
#endif
#ifdef HAVE_NEON
capfilter |= CPU_CAP_NEON;
@@ -827,20 +917,23 @@ static void alc_initconfig(void)
size_t len;
const char *next = str;
- i = 0;
do {
str = next;
- next = strchr(str, ',');
-
while(isspace(str[0]))
str++;
+ next = strchr(str, ',');
+
if(!str[0] || str[0] == ',')
continue;
len = (next ? ((size_t)(next-str)) : strlen(str));
- if(strncasecmp(str, "sse", len) == 0)
+ while(len > 0 && isspace(str[len-1]))
+ len--;
+ if(len == 3 && strncasecmp(str, "sse", len) == 0)
capfilter &= ~CPU_CAP_SSE;
- else if(strncasecmp(str, "neon", len) == 0)
+ else if(len == 4 && strncasecmp(str, "sse2", len) == 0)
+ capfilter &= ~CPU_CAP_SSE2;
+ else if(len == 4 && strncasecmp(str, "neon", len) == 0)
capfilter &= ~CPU_CAP_NEON;
else
WARN("Invalid CPU extension \"%s\"\n", str);
@@ -911,6 +1004,8 @@ static void alc_initconfig(void)
i = 0;
do {
devs = next;
+ while(isspace(devs[0]))
+ devs++;
next = strchr(devs, ',');
delitem = (devs[0] == '-');
@@ -924,7 +1019,9 @@ static void alc_initconfig(void)
endlist = 1;
len = (next ? ((size_t)(next-devs)) : strlen(devs));
- for(n = i;BackendList[n].Init;n++)
+ while(len > 0 && isspace(devs[len-1]))
+ len--;
+ for(n = i;BackendList[n].name;n++)
{
if(len == strlen(BackendList[n].name) &&
strncmp(BackendList[n].name, devs, len) == 0)
@@ -934,7 +1031,7 @@ static void alc_initconfig(void)
do {
BackendList[n] = BackendList[n+1];
++n;
- } while(BackendList[n].Init);
+ } while(BackendList[n].name);
}
else
{
@@ -956,14 +1053,39 @@ static void alc_initconfig(void)
if(endlist)
{
BackendList[i].name = NULL;
+ BackendList[i].getFactory = NULL;
BackendList[i].Init = NULL;
BackendList[i].Deinit = NULL;
BackendList[i].Probe = NULL;
}
}
- for(i = 0;BackendList[i].Init && (!PlaybackBackend.name || !CaptureBackend.name);i++)
+ for(i = 0;(BackendList[i].Init || BackendList[i].getFactory) && (!PlaybackBackend.name || !CaptureBackend.name);i++)
{
+ if(BackendList[i].getFactory)
+ {
+ ALCbackendFactory *factory = BackendList[i].getFactory();
+ if(!V0(factory,init)())
+ {
+ WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name);
+ continue;
+ }
+
+ TRACE("Initialized backend \"%s\"\n", BackendList[i].name);
+ if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback))
+ {
+ PlaybackBackend = BackendList[i];
+ TRACE("Added \"%s\" for playback\n", PlaybackBackend.name);
+ }
+ if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture))
+ {
+ CaptureBackend = BackendList[i];
+ TRACE("Added \"%s\" for capture\n", CaptureBackend.name);
+ }
+
+ continue;
+ }
+
if(!BackendList[i].Init(&BackendList[i].Funcs))
{
WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name);
@@ -982,7 +1104,10 @@ static void alc_initconfig(void)
TRACE("Added \"%s\" for capture\n", CaptureBackend.name);
}
}
- BackendLoopback.Init(&BackendLoopback.Funcs);
+ {
+ ALCbackendFactory *factory = ALCloopbackFactory_getFactory();
+ V0(factory,init)();
+ }
if(ConfigValueStr(NULL, "excludefx", &str))
{
@@ -1006,12 +1131,14 @@ static void alc_initconfig(void)
} while(next++);
}
+ InitEffectFactoryMap();
+
InitEffect(&DefaultEffect);
str = getenv("ALSOFT_DEFAULT_REVERB");
if((str && str[0]) || ConfigValueStr(NULL, "default-reverb", &str))
LoadReverbPreset(str, &DefaultEffect);
}
-#define DO_INITCONFIG() pthread_once(&alc_config_once, alc_initconfig)
+#define DO_INITCONFIG() althread_once(&alc_config_once, alc_initconfig)
/************************************************
@@ -1039,6 +1166,8 @@ static void alc_cleanup(void)
} while((dev=dev->next) != NULL);
ERR("%u device%s not closed\n", num, (num>1)?"s":"");
}
+
+ DeinitEffectFactoryMap();
}
static void alc_deinit_safe(void)
@@ -1050,7 +1179,7 @@ static void alc_deinit_safe(void)
ThunkExit();
DeleteCriticalSection(&ListLock);
- pthread_key_delete(LocalContext);
+ althread_key_delete(LocalContext);
if(LogFile != stderr)
fclose(LogFile);
@@ -1066,9 +1195,20 @@ static void alc_deinit(void)
memset(&PlaybackBackend, 0, sizeof(PlaybackBackend));
memset(&CaptureBackend, 0, sizeof(CaptureBackend));
- for(i = 0;BackendList[i].Deinit;i++)
- BackendList[i].Deinit();
- BackendLoopback.Deinit();
+ for(i = 0;BackendList[i].Deinit || BackendList[i].getFactory;i++)
+ {
+ if(!BackendList[i].getFactory)
+ BackendList[i].Deinit();
+ else
+ {
+ ALCbackendFactory *factory = BackendList[i].getFactory();
+ V0(factory,deinit)();
+ }
+ }
+ {
+ ALCbackendFactory *factory = ALCloopbackFactory_getFactory();
+ V0(factory,deinit)();
+ }
alc_deinit_safe();
}
@@ -1086,10 +1226,26 @@ static void ProbeList(ALCchar **list, size_t *listsize, enum DevProbe type)
*list = NULL;
*listsize = 0;
- if(type == ALL_DEVICE_PROBE && PlaybackBackend.Probe)
- PlaybackBackend.Probe(type);
- else if(type == CAPTURE_DEVICE_PROBE && CaptureBackend.Probe)
- CaptureBackend.Probe(type);
+ if(type == ALL_DEVICE_PROBE && (PlaybackBackend.Probe || PlaybackBackend.getFactory))
+ {
+ if(!PlaybackBackend.getFactory)
+ PlaybackBackend.Probe(type);
+ else
+ {
+ ALCbackendFactory *factory = PlaybackBackend.getFactory();
+ V(factory,probe)(type);
+ }
+ }
+ else if(type == CAPTURE_DEVICE_PROBE && (CaptureBackend.Probe || CaptureBackend.getFactory))
+ {
+ if(!CaptureBackend.getFactory)
+ CaptureBackend.Probe(type);
+ else
+ {
+ ALCbackendFactory *factory = CaptureBackend.getFactory();
+ V(factory,probe)(type);
+ }
+ }
UnlockLists();
}
@@ -1162,6 +1318,7 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans)
return "(unknown channels)";
}
+extern inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type);
ALuint BytesFromDevFmt(enum DevFmtType type)
{
switch(type)
@@ -1273,21 +1430,30 @@ static ALCboolean IsValidALCChannels(ALCenum channels)
/************************************************
* Miscellaneous ALC helpers
************************************************/
+extern inline void LockContext(ALCcontext *context);
+extern inline void UnlockContext(ALCcontext *context);
-void ALCdevice_LockDefault(ALCdevice *device)
+ALint64 ALCdevice_GetLatencyDefault(ALCdevice *UNUSED(device))
{
- EnterCriticalSection(&device->Mutex);
+ return 0;
}
-void ALCdevice_UnlockDefault(ALCdevice *device)
+
+ALint64 ALCdevice_GetLatency(ALCdevice *device)
{
- LeaveCriticalSection(&device->Mutex);
+ return V0(device->Backend,getLatency)();
}
-ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device)
+
+void ALCdevice_Lock(ALCdevice *device)
{
- (void)device;
- return 0;
+ V0(device->Backend,lock)();
+}
+
+void ALCdevice_Unlock(ALCdevice *device)
+{
+ V0(device->Backend,unlock)();
}
+
/* SetDefaultWFXChannelOrder
*
* Sets the default channel order used by WaveFormatEx.
@@ -1493,6 +1659,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS)
numSends = attrList[attrIdx + 1];
+ if(attrList[attrIdx] == ALC_HRTF_SOFT)
+ {
+ if(attrList[attrIdx + 1] != ALC_FALSE)
+ device->Flags |= DEVICE_HRTF_REQUEST;
+ else
+ device->Flags &= ~DEVICE_HRTF_REQUEST;
+ }
+
attrIdx += 2;
}
@@ -1506,7 +1680,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
numSends = minu(MAX_SENDS, numSends);
if((device->Flags&DEVICE_RUNNING))
- ALCdevice_StopPlayback(device);
+ V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
device->Frequency = freq;
@@ -1524,7 +1698,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
/* If a context is already running on the device, stop playback so the
* device attributes can be updated. */
if((device->Flags&DEVICE_RUNNING))
- ALCdevice_StopPlayback(device);
+ V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
freq = device->Frequency;
@@ -1552,6 +1726,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS)
numSends = attrList[attrIdx + 1];
+ if(attrList[attrIdx] == ALC_HRTF_SOFT)
+ {
+ if(attrList[attrIdx + 1] != ALC_FALSE)
+ device->Flags |= DEVICE_HRTF_REQUEST;
+ else
+ device->Flags &= ~DEVICE_HRTF_REQUEST;
+ }
+
attrIdx += 2;
}
@@ -1589,7 +1771,19 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->Frequency,
device->UpdateSize, device->NumUpdates);
- if(ALCdevice_ResetPlayback(device) == ALC_FALSE)
+ if((device->Flags&DEVICE_HRTF_REQUEST))
+ {
+ enum DevFmtChannels chans;
+ ALCuint freq;
+
+ FindHrtfFormat(device, &chans, &freq);
+ device->Frequency = freq;
+ device->FmtChans = chans;
+ device->Flags |= DEVICE_CHANNELS_REQUEST |
+ DEVICE_FREQUENCY_REQUEST;
+ }
+
+ if(V0(device->Backend,reset)() == ALC_FALSE)
return ALC_INVALID_DEVICE;
if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST))
@@ -1623,9 +1817,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->PendingClicks[i] = 0.0f;
}
+ V(device->Synth,update)(device);
+
device->Hrtf = NULL;
- if(device->Type != Loopback && GetConfigValueBool(NULL, "hrtf", AL_FALSE))
+ if(device->Type != Loopback && ConfigValueExists(NULL, "hrtf"))
+ {
+ if(GetConfigValueBool(NULL, "hrtf", AL_FALSE))
+ device->Flags |= DEVICE_HRTF_REQUEST;
+ else
+ device->Flags &= ~DEVICE_HRTF_REQUEST;
+ }
+ if((device->Flags&DEVICE_HRTF_REQUEST))
+ {
device->Hrtf = GetHrtf(device);
+ if(!device->Hrtf)
+ device->Flags &= ~DEVICE_HRTF_REQUEST;
+ }
TRACE("HRTF %s\n", device->Hrtf?"enabled":"disabled");
if(!device->Hrtf && device->Bs2bLevel > 0 && device->Bs2bLevel <= 6)
@@ -1669,7 +1876,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALeffectslot *slot = context->EffectSlotMap.array[pos].value;
- if(ALeffectState_DeviceUpdate(slot->EffectState, device) == AL_FALSE)
+ if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE)
{
UnlockUIntMapRead(&context->EffectSlotMap);
ALCdevice_Unlock(device);
@@ -1677,7 +1884,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
return ALC_INVALID_DEVICE;
}
slot->NeedsUpdate = AL_FALSE;
- ALeffectState_Update(slot->EffectState, device, slot);
+ V(slot->EffectState,update)(device, slot);
}
UnlockUIntMapRead(&context->EffectSlotMap);
@@ -1706,21 +1913,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALeffectslot *slot = device->DefaultSlot;
- if(ALeffectState_DeviceUpdate(slot->EffectState, device) == AL_FALSE)
+ if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE)
{
ALCdevice_Unlock(device);
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
slot->NeedsUpdate = AL_FALSE;
- ALeffectState_Update(slot->EffectState, device, slot);
+ V(slot->EffectState,update)(device, slot);
}
ALCdevice_Unlock(device);
RestoreFPUMode(&oldMode);
- if(ALCdevice_StartPlayback(device) == ALC_FALSE)
- return ALC_INVALID_DEVICE;
- device->Flags |= DEVICE_RUNNING;
+ if(!(device->Flags&DEVICE_PAUSED))
+ {
+ if(V0(device->Backend,start)() == ALC_FALSE)
+ return ALC_INVALID_DEVICE;
+ device->Flags |= DEVICE_RUNNING;
+ }
return ALC_NO_ERROR;
}
@@ -1734,17 +1944,24 @@ static ALCvoid FreeDevice(ALCdevice *device)
{
TRACE("%p\n", device);
- if(device->Type != Capture)
- ALCdevice_ClosePlayback(device);
- else
- ALCdevice_CloseCapture(device);
+ V0(device->Backend,close)();
+ DELETE_OBJ(device->Backend);
+ device->Backend = NULL;
+
+ DELETE_OBJ(device->Synth);
+ device->Synth = NULL;
if(device->DefaultSlot)
{
- ALeffectState_Destroy(device->DefaultSlot->EffectState);
- device->DefaultSlot->EffectState = NULL;
+ ALeffectState *state = device->DefaultSlot->EffectState;
+ device->DefaultSlot = NULL;
+ DELETE_OBJ(state);
}
+ if(device->DefaultSfont)
+ ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
+ device->DefaultSfont = NULL;
+
if(device->BufferMap.size > 0)
{
WARN("(%p) Deleting %d Buffer(s)\n", device, device->BufferMap.size);
@@ -1766,14 +1983,33 @@ static ALCvoid FreeDevice(ALCdevice *device)
}
ResetUIntMap(&device->FilterMap);
+ if(device->SfontMap.size > 0)
+ {
+ WARN("(%p) Deleting %d Soundfont(s)\n", device, device->SfontMap.size);
+ ReleaseALSoundfonts(device);
+ }
+ ResetUIntMap(&device->SfontMap);
+
+ if(device->PresetMap.size > 0)
+ {
+ WARN("(%p) Deleting %d Preset(s)\n", device, device->PresetMap.size);
+ ReleaseALPresets(device);
+ }
+ ResetUIntMap(&device->PresetMap);
+
+ if(device->FontsoundMap.size > 0)
+ {
+ WARN("(%p) Deleting %d Fontsound(s)\n", device, device->FontsoundMap.size);
+ ReleaseALFontsounds(device);
+ }
+ ResetUIntMap(&device->FontsoundMap);
+
free(device->Bs2b);
device->Bs2b = NULL;
free(device->DeviceName);
device->DeviceName = NULL;
- DeleteCriticalSection(&device->Mutex);
-
al_free(device);
}
@@ -1916,10 +2152,10 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
{
ALCcontext *volatile*tmp_ctx;
- if(pthread_getspecific(LocalContext) == context)
+ if(althread_getspecific(LocalContext) == context)
{
WARN("%p released while current on thread\n", context);
- pthread_setspecific(LocalContext, NULL);
+ althread_setspecific(LocalContext, NULL);
ALCcontext_DecRef(context);
}
@@ -2000,7 +2236,7 @@ ALCcontext *GetContextRef(void)
{
ALCcontext *context;
- context = pthread_getspecific(LocalContext);
+ context = althread_getspecific(LocalContext);
if(context)
ALCcontext_IncRef(context);
else
@@ -2044,18 +2280,16 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
*
* Not functional
*/
-ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *Context)
+ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *UNUSED(context))
{
- (void)Context;
}
/* alcProcessContext
*
* Not functional
*/
-ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *Context)
+ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *UNUSED(context))
{
- (void)Context;
}
@@ -2231,7 +2465,7 @@ ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsi
{
case ALC_CAPTURE_SAMPLES:
ALCdevice_Lock(device);
- *data = ALCdevice_AvailableSamples(device);
+ *data = V0(device->Backend,availableSamples)();
ALCdevice_Unlock(device);
break;
@@ -2265,11 +2499,11 @@ ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsi
break;
case ALC_ATTRIBUTES_SIZE:
- *data = 13;
+ *data = 15;
break;
case ALC_ALL_ATTRIBUTES:
- if(size < 13)
+ if(size < 15)
alcSetError(device, ALC_INVALID_VALUE);
else
{
@@ -2304,6 +2538,9 @@ ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsi
data[i++] = ALC_MAX_AUXILIARY_SENDS;
data[i++] = device->NumAuxSends;
+ data[i++] = ALC_HRTF_SOFT;
+ data[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE);
+
data[i++] = 0;
}
break;
@@ -2356,6 +2593,10 @@ ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsi
*data = device->Connected;
break;
+ case ALC_HRTF_SOFT:
+ *data = (device->Hrtf ? ALC_TRUE : ALC_FALSE);
+ break;
+
default:
alcSetError(device, ALC_INVALID_ENUM);
break;
@@ -2504,7 +2745,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
{
if(!device->ContextList)
{
- ALCdevice_StopPlayback(device);
+ V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
}
UnlockLists();
@@ -2548,7 +2789,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
ReleaseContext(context, Device);
if(!Device->ContextList)
{
- ALCdevice_StopPlayback(Device);
+ V0(Device->Backend,stop)();
Device->Flags &= ~DEVICE_RUNNING;
}
}
@@ -2564,7 +2805,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
{
ALCcontext *Context;
- Context = pthread_getspecific(LocalContext);
+ Context = althread_getspecific(LocalContext);
if(!Context) Context = GlobalContext;
return Context;
@@ -2577,7 +2818,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
{
ALCcontext *Context;
- Context = pthread_getspecific(LocalContext);
+ Context = althread_getspecific(LocalContext);
return Context;
}
@@ -2599,9 +2840,9 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
context = ExchangePtr((XchgPtr*)&GlobalContext, context);
if(context) ALCcontext_DecRef(context);
- if((context=pthread_getspecific(LocalContext)) != NULL)
+ if((context=althread_getspecific(LocalContext)) != NULL)
{
- pthread_setspecific(LocalContext, NULL);
+ althread_setspecific(LocalContext, NULL);
ALCcontext_DecRef(context);
}
@@ -2623,8 +2864,8 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
return ALC_FALSE;
}
/* context's reference count is already incremented */
- old = pthread_getspecific(LocalContext);
- pthread_setspecific(LocalContext, context);
+ old = althread_getspecific(LocalContext);
+ althread_setspecific(LocalContext, context);
if(old) ALCcontext_DecRef(old);
return ALC_TRUE;
@@ -2680,11 +2921,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
//Validate device
- device->Funcs = &PlaybackBackend.Funcs;
device->ref = 1;
device->Connected = ALC_TRUE;
device->Type = Playback;
- InitializeCriticalSection(&device->Mutex);
device->LastError = ALC_NO_ERROR;
device->Flags = 0;
@@ -2701,6 +2940,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
+ InitUIntMap(&device->SfontMap, ~0);
+ InitUIntMap(&device->PresetMap, ~0);
+ InitUIntMap(&device->FontsoundMap, ~0);
//Set output format
device->FmtChans = DevFmtChannelsDefault;
@@ -2709,6 +2951,24 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->NumUpdates = 4;
device->UpdateSize = 1024;
+ if(!PlaybackBackend.getFactory)
+ {
+ device->Funcs = &PlaybackBackend.Funcs;
+ device->Backend = create_backend_wrapper(device, ALCbackend_Playback);
+ }
+ else
+ {
+ ALCbackendFactory *factory = PlaybackBackend.getFactory();
+ device->Backend = V(factory,createBackend)(device, ALCbackend_Playback);
+ }
+ if(!device->Backend)
+ {
+ al_free(device);
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
+
if(ConfigValueStr(NULL, "channels", &fmt))
{
static const struct {
@@ -2844,10 +3104,20 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->NumStereoSources = 1;
device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
+ device->Synth = SynthCreate(device);
+ if(!device->Synth)
+ {
+ DELETE_OBJ(device->Backend);
+ al_free(device);
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
// Find a playback device to open
- if((err=ALCdevice_OpenPlayback(device, deviceName)) != ALC_NO_ERROR)
+ if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR)
{
- DeleteCriticalSection(&device->Mutex);
+ DELETE_OBJ(device->Synth);
+ DELETE_OBJ(device->Backend);
al_free(device);
alcSetError(NULL, err);
return NULL;
@@ -2863,8 +3133,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
else if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR)
{
- ALeffectState_Destroy(device->DefaultSlot->EffectState);
+ ALeffectState *state = device->DefaultSlot->EffectState;
device->DefaultSlot = NULL;
+ DELETE_OBJ(state);
ERR("Failed to initialize the default effect\n");
}
}
@@ -2907,7 +3178,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *Device)
ReleaseContext(ctx, Device);
}
if((Device->Flags&DEVICE_RUNNING))
- ALCdevice_StopPlayback(Device);
+ V0(Device->Backend,stop)();
Device->Flags &= ~DEVICE_RUNNING;
ALCdevice_DecRef(Device);
@@ -2949,25 +3220,42 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
}
//Validate device
- device->Funcs = &CaptureBackend.Funcs;
device->ref = 1;
device->Connected = ALC_TRUE;
device->Type = Capture;
- InitializeCriticalSection(&device->Mutex);
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
+ InitUIntMap(&device->SfontMap, ~0);
+ InitUIntMap(&device->PresetMap, ~0);
+ InitUIntMap(&device->FontsoundMap, ~0);
device->DeviceName = NULL;
+ if(!CaptureBackend.getFactory)
+ {
+ device->Funcs = &CaptureBackend.Funcs;
+ device->Backend = create_backend_wrapper(device, ALCbackend_Capture);
+ }
+ else
+ {
+ ALCbackendFactory *factory = CaptureBackend.getFactory();
+ device->Backend = V(factory,createBackend)(device, ALCbackend_Capture);
+ }
+ if(!device->Backend)
+ {
+ al_free(device);
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
device->Flags |= DEVICE_FREQUENCY_REQUEST;
device->Frequency = frequency;
device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST;
if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE)
{
- DeleteCriticalSection(&device->Mutex);
al_free(device);
alcSetError(NULL, ALC_INVALID_ENUM);
return NULL;
@@ -2976,9 +3264,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
device->UpdateSize = samples;
device->NumUpdates = 1;
- if((err=ALCdevice_OpenCapture(device, deviceName)) != ALC_NO_ERROR)
+ if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR)
{
- DeleteCriticalSection(&device->Mutex);
al_free(device);
alcSetError(NULL, err);
return NULL;
@@ -3026,7 +3313,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
if(device->Connected)
{
if(!(device->Flags&DEVICE_RUNNING))
- ALCdevice_StartCapture(device);
+ V0(device->Backend,start)();
device->Flags |= DEVICE_RUNNING;
}
ALCdevice_Unlock(device);
@@ -3043,7 +3330,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
{
ALCdevice_Lock(device);
if((device->Flags&DEVICE_RUNNING))
- ALCdevice_StopCapture(device);
+ V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
ALCdevice_Unlock(device);
}
@@ -3053,15 +3340,15 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
{
- if(!(device=VerifyDevice(device)) && device->Type != Capture)
+ if(!(device=VerifyDevice(device)) || device->Type != Capture)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
ALCenum err = ALC_INVALID_VALUE;
ALCdevice_Lock(device);
- if(samples >= 0 && ALCdevice_AvailableSamples(device) >= (ALCuint)samples)
- err = ALCdevice_CaptureSamples(device, buffer, samples);
+ if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples)
+ err = V(device->Backend,captureSamples)(buffer, samples);
ALCdevice_Unlock(device);
if(err != ALC_NO_ERROR)
@@ -3081,6 +3368,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer,
*/
ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName)
{
+ ALCbackendFactory *factory;
ALCdevice *device;
DO_INITCONFIG();
@@ -3100,11 +3388,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
}
//Validate device
- device->Funcs = &BackendLoopback.Funcs;
device->ref = 1;
device->Connected = ALC_TRUE;
device->Type = Loopback;
- InitializeCriticalSection(&device->Mutex);
device->LastError = ALC_NO_ERROR;
device->Flags = 0;
@@ -3121,6 +3407,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
+ InitUIntMap(&device->SfontMap, ~0);
+ InitUIntMap(&device->PresetMap, ~0);
+ InitUIntMap(&device->FontsoundMap, ~0);
+
+ factory = ALCloopbackFactory_getFactory();
+ device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback);
+ if(!device->Backend)
+ {
+ al_free(device);
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
//Set output format
device->NumUpdates = 0;
@@ -3142,8 +3440,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
device->NumStereoSources = 1;
device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
+ device->Synth = SynthCreate(device);
+ if(!device->Synth)
+ {
+ DELETE_OBJ(device->Backend);
+ al_free(device);
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
// Open the "backend"
- ALCdevice_OpenPlayback(device, "Loopback");
+ V(device->Backend,open)("Loopback");
do {
device->next = DeviceList;
} while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device));
@@ -3181,7 +3488,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device
* Renders some samples into a buffer, using the format last set by the
* attributes given to alcCreateContext.
*/
-ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
+FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
{
if(!(device=VerifyDevice(device)) || device->Type != Loopback)
alcSetError(device, ALC_INVALID_DEVICE);
@@ -3191,3 +3498,59 @@ ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffe
aluMixData(device, buffer, samples);
if(device) ALCdevice_DecRef(device);
}
+
+
+/************************************************
+ * ALC DSP pause/resume functions
+ ************************************************/
+
+/* alcDevicePauseSOFT
+ *
+ * Pause the DSP to stop audio processing.
+ */
+ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
+{
+ if(!(device=VerifyDevice(device)) || device->Type != Playback)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ {
+ LockLists();
+ if((device->Flags&DEVICE_RUNNING))
+ V0(device->Backend,stop)();
+ device->Flags &= ~DEVICE_RUNNING;
+ device->Flags |= DEVICE_PAUSED;
+ UnlockLists();
+ }
+ if(device) ALCdevice_DecRef(device);
+}
+
+/* alcDeviceResumeSOFT
+ *
+ * Resume the DSP to restart audio processing.
+ */
+ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
+{
+ if(!(device=VerifyDevice(device)) || device->Type != Playback)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ {
+ LockLists();
+ if((device->Flags&DEVICE_PAUSED))
+ {
+ if(V0(device->Backend,start)() != ALC_FALSE)
+ {
+ device->Flags |= DEVICE_RUNNING;
+ device->Flags &= ~DEVICE_PAUSED;
+ }
+ else
+ {
+ alcSetError(device, ALC_INVALID_DEVICE);
+ ALCdevice_Lock(device);
+ aluHandleDisconnect(device);
+ ALCdevice_Unlock(device);
+ }
+ }
+ UnlockLists();
+ }
+ if(device) ALCdevice_DecRef(device);
+}
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 282053c7..34ac6687 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -36,6 +36,8 @@
#include "mixer_defs.h"
+#include "midi/base.h"
+
struct ChanMap {
enum Channel channel;
@@ -48,6 +50,32 @@ ALfloat ConeScale = 1.0f;
/* Localized Z scalar for mono sources */
ALfloat ZScale = 1.0f;
+extern inline ALfloat minf(ALfloat a, ALfloat b);
+extern inline ALfloat maxf(ALfloat a, ALfloat b);
+extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
+
+extern inline ALdouble mind(ALdouble a, ALdouble b);
+extern inline ALdouble maxd(ALdouble a, ALdouble b);
+extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
+
+extern inline ALuint minu(ALuint a, ALuint b);
+extern inline ALuint maxu(ALuint a, ALuint b);
+extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
+
+extern inline ALint mini(ALint a, ALint b);
+extern inline ALint maxi(ALint a, ALint b);
+extern inline ALint clampi(ALint val, ALint min, ALint max);
+
+extern inline ALint64 mini64(ALint64 a, ALint64 b);
+extern inline ALint64 maxi64(ALint64 a, ALint64 b);
+extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
+
+extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
+extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
+extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
+
+extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
+extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
static ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
{
@@ -105,20 +133,20 @@ static WetMixerFunc SelectSendMixer(void)
}
-static __inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
+static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
{
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
}
-static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
+static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
{
return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
inVector1[2]*inVector2[2];
}
-static __inline void aluNormalize(ALfloat *inVector)
+static inline void aluNormalize(ALfloat *inVector)
{
ALfloat lengthsqr = aluDotproduct(inVector, inVector);
if(lengthsqr > 0.0f)
@@ -130,7 +158,7 @@ static __inline void aluNormalize(ALfloat *inVector)
}
}
-static __inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*RESTRICT matrix)[4])
+static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
{
ALfloat temp[4] = {
vector[0], vector[1], vector[2], w
@@ -194,49 +222,49 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
static const struct ChanMap StereoMap[2] = {
- { FrontLeft, -30.0f * F_PI/180.0f },
- { FrontRight, 30.0f * F_PI/180.0f }
+ { FrontLeft, DEG2RAD(-30.0f) },
+ { FrontRight, DEG2RAD( 30.0f) }
};
static const struct ChanMap StereoWideMap[2] = {
- { FrontLeft, -90.0f * F_PI/180.0f },
- { FrontRight, 90.0f * F_PI/180.0f }
+ { FrontLeft, DEG2RAD(-90.0f) },
+ { FrontRight, DEG2RAD( 90.0f) }
};
static const struct ChanMap RearMap[2] = {
- { BackLeft, -150.0f * F_PI/180.0f },
- { BackRight, 150.0f * F_PI/180.0f }
+ { BackLeft, DEG2RAD(-150.0f) },
+ { BackRight, DEG2RAD( 150.0f) }
};
static const struct ChanMap QuadMap[4] = {
- { FrontLeft, -45.0f * F_PI/180.0f },
- { FrontRight, 45.0f * F_PI/180.0f },
- { BackLeft, -135.0f * F_PI/180.0f },
- { BackRight, 135.0f * F_PI/180.0f }
+ { FrontLeft, DEG2RAD( -45.0f) },
+ { FrontRight, DEG2RAD( 45.0f) },
+ { BackLeft, DEG2RAD(-135.0f) },
+ { BackRight, DEG2RAD( 135.0f) }
};
static const struct ChanMap X51Map[6] = {
- { FrontLeft, -30.0f * F_PI/180.0f },
- { FrontRight, 30.0f * F_PI/180.0f },
- { FrontCenter, 0.0f * F_PI/180.0f },
+ { FrontLeft, DEG2RAD( -30.0f) },
+ { FrontRight, DEG2RAD( 30.0f) },
+ { FrontCenter, DEG2RAD( 0.0f) },
{ LFE, 0.0f },
- { BackLeft, -110.0f * F_PI/180.0f },
- { BackRight, 110.0f * F_PI/180.0f }
+ { BackLeft, DEG2RAD(-110.0f) },
+ { BackRight, DEG2RAD( 110.0f) }
};
static const struct ChanMap X61Map[7] = {
- { FrontLeft, -30.0f * F_PI/180.0f },
- { FrontRight, 30.0f * F_PI/180.0f },
- { FrontCenter, 0.0f * F_PI/180.0f },
+ { FrontLeft, DEG2RAD(-30.0f) },
+ { FrontRight, DEG2RAD( 30.0f) },
+ { FrontCenter, DEG2RAD( 0.0f) },
{ LFE, 0.0f },
- { BackCenter, 180.0f * F_PI/180.0f },
- { SideLeft, -90.0f * F_PI/180.0f },
- { SideRight, 90.0f * F_PI/180.0f }
+ { BackCenter, DEG2RAD(180.0f) },
+ { SideLeft, DEG2RAD(-90.0f) },
+ { SideRight, DEG2RAD( 90.0f) }
};
static const struct ChanMap X71Map[8] = {
- { FrontLeft, -30.0f * F_PI/180.0f },
- { FrontRight, 30.0f * F_PI/180.0f },
- { FrontCenter, 0.0f * F_PI/180.0f },
+ { FrontLeft, DEG2RAD( -30.0f) },
+ { FrontRight, DEG2RAD( 30.0f) },
+ { FrontCenter, DEG2RAD( 0.0f) },
{ LFE, 0.0f },
- { BackLeft, -150.0f * F_PI/180.0f },
- { BackRight, 150.0f * F_PI/180.0f },
- { SideLeft, -90.0f * F_PI/180.0f },
- { SideRight, 90.0f * F_PI/180.0f }
+ { BackLeft, DEG2RAD(-150.0f) },
+ { BackRight, DEG2RAD( 150.0f) },
+ { SideLeft, DEG2RAD( -90.0f) },
+ { SideRight, DEG2RAD( 90.0f) }
};
ALCdevice *Device = ALContext->Device;
@@ -254,7 +282,6 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALboolean DirectChannels;
ALfloat hwidth = 0.0f;
ALfloat Pitch;
- ALfloat cw;
ALint i, c;
/* Get device properties */
@@ -280,14 +307,9 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALbuffer *ALBuffer;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
- ALsizei maxstep = BUFFERSIZE;
- maxstep -= ResamplerPadding[Resampler] +
- ResamplerPrePadding[Resampler] + 1;
- maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
-
Pitch = Pitch * ALBuffer->Frequency / Frequency;
- if(Pitch > (ALfloat)maxstep)
- ALSource->Params.Step = maxstep<<FRACTIONBITS;
+ if(Pitch > 10.0f)
+ ALSource->Params.Step = 10<<FRACTIONBITS;
else
{
ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
@@ -319,7 +341,7 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
SrcMatrix = ALSource->Params.Direct.Gains;
- for(i = 0;i < MaxChannels;i++)
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
{
for(c = 0;c < MaxChannels;c++)
SrcMatrix[i][c] = 0.0f;
@@ -345,7 +367,7 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
else
{
chans = StereoWideMap;
- hwidth = 60.0f * F_PI/180.0f;
+ hwidth = DEG2RAD(60.0f);
}
num_channels = 2;
break;
@@ -443,27 +465,37 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
for(i = 0;i < NumSends;i++)
{
ALeffectslot *Slot = ALSource->Send[i].Slot;
-
if(!Slot && i == 0)
Slot = Device->DefaultSlot;
- if(Slot && Slot->effect.type == AL_EFFECT_NULL)
- Slot = NULL;
- ALSource->Params.Send[i].Slot = Slot;
+ if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
+ {
+ ALSource->Params.Send[i].OutBuffer = NULL;
+ ALSource->Params.Send[i].ClickRemoval = NULL;
+ ALSource->Params.Send[i].PendingClicks = NULL;
+ }
+ else
+ {
+ ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
+ ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
+ ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
+ }
ALSource->Params.Send[i].Gain = WetGain[i];
}
- /* Update filter coefficients. Calculations based on the I3DL2
- * spec. */
- cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
-
- /* We use two chained one-pole filters, so we need to take the
- * square root of the squared gain, which is the same as the base
- * gain. */
- ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
+ {
+ ALfloat gain = maxf(0.01f, DryGainHF);
+ for(c = 0;c < num_channels;c++)
+ ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[c],
+ ALfilterType_HighShelf, gain,
+ (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ }
for(i = 0;i < NumSends;i++)
{
- ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
- ALSource->Params.Send[i].iirFilter.coeff = a;
+ ALfloat gain = maxf(0.01f, WetGainHF[i]);
+ for(c = 0;c < num_channels;c++)
+ ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[c],
+ ALfilterType_HighShelf, gain,
+ (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
}
}
@@ -495,7 +527,6 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALfloat Pitch;
ALuint Frequency;
ALint NumSends;
- ALfloat cw;
ALint i, j;
DryGainHF = 1.0f;
@@ -547,7 +578,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
if(!Slot && i == 0)
Slot = Device->DefaultSlot;
- if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
+ if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
{
Slot = NULL;
RoomRolloff[i] = 0.0f;
@@ -557,12 +588,12 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
else if(Slot->AuxSendAuto)
{
RoomRolloff[i] = RoomRolloffBase;
- if(IsReverbEffect(Slot->effect.type))
+ if(IsReverbEffect(Slot->EffectType))
{
- RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor;
- DecayDistance[i] = Slot->effect.Reverb.DecayTime *
+ RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
+ DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
SPEEDOFSOUNDMETRESPERSEC;
- RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF;
+ RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
}
else
{
@@ -579,13 +610,24 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
RoomAirAbsorption[i] = AIRABSORBGAINHF;
}
- ALSource->Params.Send[i].Slot = Slot;
+ if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
+ {
+ ALSource->Params.Send[i].OutBuffer = NULL;
+ ALSource->Params.Send[i].ClickRemoval = NULL;
+ ALSource->Params.Send[i].PendingClicks = NULL;
+ }
+ else
+ {
+ ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
+ ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
+ ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
+ }
}
/* Transform source to listener space (convert to head relative) */
if(ALSource->HeadRelative == AL_FALSE)
{
- ALfloat (*RESTRICT Matrix)[4] = ALContext->Listener->Params.Matrix;
+ ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
/* Transform source vectors */
aluMatrixVector(Position, 1.0f, Matrix);
aluMatrixVector(Direction, 0.0f, Matrix);
@@ -704,7 +746,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
/* Calculate directional soundcones */
- Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI);
+ Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
if(Angle > InnerAngle && Angle <= OuterAngle)
{
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
@@ -777,14 +819,9 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
/* Calculate fixed-point stepping value, based on the pitch, buffer
* frequency, and output frequency. */
- ALsizei maxstep = BUFFERSIZE;
- maxstep -= ResamplerPadding[Resampler] +
- ResamplerPrePadding[Resampler] + 1;
- maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
-
Pitch = Pitch * ALBuffer->Frequency / Frequency;
- if(Pitch > (ALfloat)maxstep)
- ALSource->Params.Step = maxstep<<FRACTIONBITS;
+ if(Pitch > 10.0f)
+ ALSource->Params.Step = 10<<FRACTIONBITS;
else
{
ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
@@ -869,7 +906,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALfloat DirGain = 0.0f;
ALfloat AmbientGain;
- for(i = 0;i < MaxChannels;i++)
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
{
for(j = 0;j < MaxChannels;j++)
Matrix[i][j] = 0.0f;
@@ -900,51 +937,59 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
for(i = 0;i < NumSends;i++)
ALSource->Params.Send[i].Gain = WetGain[i];
- /* Update filter coefficients. */
- cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
- ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
+ {
+ ALfloat gain = maxf(0.01f, DryGainHF);
+ ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[0],
+ ALfilterType_HighShelf, gain,
+ (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
+ }
for(i = 0;i < NumSends;i++)
{
- ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
- ALSource->Params.Send[i].iirFilter.coeff = a;
+ ALfloat gain = maxf(0.01f, WetGainHF[i]);
+ ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[0],
+ ALfilterType_HighShelf, gain,
+ (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
}
}
-static __inline ALfloat aluF2F(ALfloat val)
-{ return val; }
-static __inline ALint aluF2I(ALfloat val)
+static inline ALint aluF2I25(ALfloat val)
{
- /* Clamp the value between -1 and +1. This handles that without branching. */
- val = val+1.0f - fabsf(val-1.0f);
- val = (val-2.0f + fabsf(val+2.0f)) * 0.25f;
- /* Convert to a signed integer, between -2147483647 and +2147483647. */
- return fastf2i((ALfloat)(val*2147483647.0));
+ /* Clamp the value between -1 and +1. This handles that with only a single branch. */
+ if(fabsf(val) > 1.0f)
+ val = (ALfloat)((0.0f < val) - (val < 0.0f));
+ /* Convert to a signed integer, between -16777215 and +16777215. */
+ return fastf2i(val*16777215.0f);
}
-static __inline ALuint aluF2UI(ALfloat val)
+
+static inline ALfloat aluF2F(ALfloat val)
+{ return val; }
+static inline ALint aluF2I(ALfloat val)
+{ return aluF2I25(val)<<7; }
+static inline ALuint aluF2UI(ALfloat val)
{ return aluF2I(val)+2147483648u; }
-static __inline ALshort aluF2S(ALfloat val)
-{ return aluF2I(val)>>16; }
-static __inline ALushort aluF2US(ALfloat val)
+static inline ALshort aluF2S(ALfloat val)
+{ return aluF2I25(val)>>9; }
+static inline ALushort aluF2US(ALfloat val)
{ return aluF2S(val)+32768; }
-static __inline ALbyte aluF2B(ALfloat val)
-{ return aluF2I(val)>>24; }
-static __inline ALubyte aluF2UB(ALfloat val)
+static inline ALbyte aluF2B(ALfloat val)
+{ return aluF2I25(val)>>17; }
+static inline ALubyte aluF2UB(ALfloat val)
{ return aluF2B(val)+128; }
#define DECL_TEMPLATE(T, func) \
-static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \
+static int Write_##T(ALCdevice *device, T *restrict buffer, \
ALuint SamplesToDo) \
{ \
- ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
+ ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
const ALuint *offsets = device->ChannelOffsets; \
ALuint i, j; \
\
for(j = 0;j < MaxChannels;j++) \
{ \
- T *RESTRICT out; \
+ T *restrict out; \
\
if(offsets[j] == INVALID_OFFSET) \
continue; \
@@ -985,6 +1030,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
ALCdevice_Lock(device);
+ V(device->Synth,process)(SamplesToDo, device->DryBuffer);
+
ctx = device->ContextList;
while(ctx)
{
@@ -1034,10 +1081,10 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
(*slot)->PendingClicks[0] = 0.0f;
if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- ALeffectState_Update((*slot)->EffectState, device, *slot);
+ V((*slot)->EffectState,update)(device, *slot);
- ALeffectState_Process((*slot)->EffectState, SamplesToDo,
- (*slot)->WetBuffer[0], device->DryBuffer);
+ V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
+ device->DryBuffer);
for(i = 0;i < SamplesToDo;i++)
(*slot)->WetBuffer[0][i] = 0.0f;
@@ -1063,10 +1110,10 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
(*slot)->PendingClicks[0] = 0.0f;
if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- ALeffectState_Update((*slot)->EffectState, device, *slot);
+ V((*slot)->EffectState,update)(device, *slot);
- ALeffectState_Process((*slot)->EffectState, SamplesToDo,
- (*slot)->WetBuffer[0], device->DryBuffer);
+ V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
+ device->DryBuffer);
for(i = 0;i < SamplesToDo;i++)
(*slot)->WetBuffer[0][i] = 0.0f;
diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c
index 49a02b23..98c0df32 100644
--- a/Alc/alcConfig.c
+++ b/Alc/alcConfig.c
@@ -45,161 +45,133 @@ typedef struct ConfigEntry {
} ConfigEntry;
typedef struct ConfigBlock {
- char *name;
ConfigEntry *entries;
unsigned int entryCount;
} ConfigBlock;
-static ConfigBlock *cfgBlocks;
-static unsigned int cfgCount;
+static ConfigBlock cfgBlock;
static char buffer[1024];
+static char *lstrip(char *line)
+{
+ while(isspace(line[0]))
+ line++;
+ return line;
+}
+
+static char *rstrip(char *line)
+{
+ size_t len = strlen(line);
+ while(len > 0 && isspace(line[len-1]))
+ len--;
+ line[len] = 0;
+ return line;
+}
+
static void LoadConfigFromFile(FILE *f)
{
- ConfigBlock *curBlock = cfgBlocks;
+ char curSection[128] = "";
ConfigEntry *ent;
while(fgets(buffer, sizeof(buffer), f))
{
- int i = 0;
+ char *line, *comment;
+ char key[256] = "";
+ char value[256] = "";
- while(isspace(buffer[i]))
- i++;
- if(!buffer[i] || buffer[i] == '#')
- continue;
+ comment = strchr(buffer, '#');
+ if(comment)
+ {
+ *(comment++) = 0;
+ comment = rstrip(lstrip(comment));
+ }
- memmove(buffer, buffer+i, strlen(buffer+i)+1);
+ line = rstrip(lstrip(buffer));
+ if(!line[0])
+ continue;
- if(buffer[0] == '[')
+ if(line[0] == '[')
{
- ConfigBlock *nextBlock;
- unsigned int i;
+ char *section = line+1;
+ char *endsection;
- i = 1;
- while(buffer[i] && buffer[i] != ']')
- i++;
-
- if(!buffer[i])
+ endsection = strchr(section, ']');
+ if(!endsection || section == endsection || endsection[1] != 0)
{
- ERR("config parse error: bad line \"%s\"\n", buffer);
+ ERR("config parse error: bad line \"%s\"\n", line);
continue;
}
- buffer[i] = 0;
-
- do {
- i++;
- if(buffer[i] && !isspace(buffer[i]))
- {
- if(buffer[i] != '#')
- WARN("config warning: extra data after block: \"%s\"\n", buffer+i);
- break;
- }
- } while(buffer[i]);
-
- nextBlock = NULL;
- for(i = 0;i < cfgCount;i++)
- {
- if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0)
- {
- nextBlock = cfgBlocks+i;
- TRACE("found block '%s'\n", nextBlock->name);
- break;
- }
- }
+ *endsection = 0;
- if(!nextBlock)
+ if(strcasecmp(section, "general") == 0)
+ curSection[0] = 0;
+ else
{
- nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock));
- if(!nextBlock)
- {
- ERR("config parse error: error reallocating config blocks\n");
- continue;
- }
- cfgBlocks = nextBlock;
- nextBlock = cfgBlocks+cfgCount;
- cfgCount++;
-
- nextBlock->name = strdup(buffer+1);
- nextBlock->entries = NULL;
- nextBlock->entryCount = 0;
-
- TRACE("found new block '%s'\n", nextBlock->name);
+ strncpy(curSection, section, sizeof(curSection)-1);
+ curSection[sizeof(curSection)-1] = 0;
}
- curBlock = nextBlock;
- continue;
- }
- /* Look for the option name */
- i = 0;
- while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' &&
- !isspace(buffer[i]))
- i++;
-
- if(!buffer[i] || buffer[i] == '#' || i == 0)
- {
- ERR("config parse error: malformed option line: \"%s\"\n", buffer);
continue;
}
- /* Seperate the option */
- if(buffer[i] != '=')
+ if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
+ sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
+ sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
{
- buffer[i++] = 0;
-
- while(isspace(buffer[i]))
- i++;
- if(buffer[i] != '=')
- {
- ERR("config parse error: option without a value: \"%s\"\n", buffer);
- continue;
- }
- }
- /* Find the start of the value */
- buffer[i++] = 0;
- while(isspace(buffer[i]))
- i++;
+ /* sscanf doesn't handle '' or "" as empty values, so clip it
+ * manually. */
+ if(strcmp(value, "\"\"") == 0 || strcmp(value, "''") == 0)
+ value[0] = 0;
+ }
+ else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
+ {
+ /* Special case for 'key =' */
+ value[0] = 0;
+ }
+ else
+ {
+ ERR("config parse error: malformed option line: \"%s\"\n\n", line);
+ continue;
+ }
+ rstrip(key);
+
+ if(curSection[0] != 0)
+ {
+ size_t len = strlen(curSection);
+ memmove(&key[len+1], key, sizeof(key)-1-len);
+ key[len] = '/';
+ memcpy(key, curSection, len);
+ }
/* Check if we already have this option set */
- ent = curBlock->entries;
- while((unsigned int)(ent-curBlock->entries) < curBlock->entryCount)
+ ent = cfgBlock.entries;
+ while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount)
{
- if(strcasecmp(ent->key, buffer) == 0)
+ if(strcasecmp(ent->key, key) == 0)
break;
ent++;
}
- if((unsigned int)(ent-curBlock->entries) >= curBlock->entryCount)
+ if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount)
{
/* Allocate a new option entry */
- ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry));
+ ent = realloc(cfgBlock.entries, (cfgBlock.entryCount+1)*sizeof(ConfigEntry));
if(!ent)
{
ERR("config parse error: error reallocating config entries\n");
continue;
}
- curBlock->entries = ent;
- ent = curBlock->entries + curBlock->entryCount;
- curBlock->entryCount++;
+ cfgBlock.entries = ent;
+ ent = cfgBlock.entries + cfgBlock.entryCount;
+ cfgBlock.entryCount++;
- ent->key = strdup(buffer);
+ ent->key = strdup(key);
ent->value = NULL;
}
- /* Look for the end of the line (Null term, new-line, or #-symbol) and
- eat up the trailing whitespace */
- memmove(buffer, buffer+i, strlen(buffer+i)+1);
-
- i = 0;
- while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n')
- i++;
- do {
- i--;
- } while(i >= 0 && isspace(buffer[i]));
- buffer[++i] = 0;
-
free(ent->value);
- ent->value = strdup(buffer);
+ ent->value = strdup(value);
TRACE("found '%s' = '%s'\n", ent->key, ent->value);
}
@@ -210,15 +182,13 @@ void ReadALConfig(void)
const char *str;
FILE *f;
- cfgBlocks = calloc(1, sizeof(ConfigBlock));
- cfgBlocks->name = strdup("general");
- cfgCount = 1;
-
#ifdef _WIN32
if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
size_t p = strlen(buffer);
snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
+
+ TRACE("Loading config %s...\n", buffer);
f = fopen(buffer, "rt");
if(f)
{
@@ -227,15 +197,75 @@ void ReadALConfig(void)
}
}
#else
- f = fopen("/etc/openal/alsoft.conf", "r");
+ str = "/etc/openal/alsoft.conf";
+
+ TRACE("Loading config %s...\n", str);
+ f = fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
+
+ if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0)
+ str = "/etc/xdg";
+ strncpy(buffer, str, sizeof(buffer)-1);
+ buffer[sizeof(buffer)-1] = 0;
+ /* Go through the list in reverse, since "the order of base directories
+ * denotes their importance; the first directory listed is the most
+ * important". Ergo, we need to load the settings from the later dirs
+ * first so that the settings in the earlier dirs override them.
+ */
+ while(1)
+ {
+ char *next = strrchr(buffer, ':');
+ if(next) *(next++) = 0;
+ else next = buffer;
+
+ if(next[0] != '/')
+ WARN("Ignoring XDG config dir: %s\n", next);
+ else
+ {
+ size_t len = strlen(next);
+ strncpy(next+len, "/alsoft.conf", buffer+sizeof(buffer)-next-len);
+ buffer[sizeof(buffer)-1] = 0;
+
+ TRACE("Loading config %s...\n", next);
+ f = fopen(next, "r");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+ if(next == buffer)
+ break;
+ }
+
if((str=getenv("HOME")) != NULL && *str)
{
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
+
+ TRACE("Loading config %s...\n", buffer);
+ f = fopen(buffer, "r");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+
+ if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0)
+ snprintf(buffer, sizeof(buffer), "%s/%s", str, "alsoft.conf");
+ else
+ {
+ buffer[0] = 0;
+ if((str=getenv("HOME")) != NULL && str[0] != 0)
+ snprintf(buffer, sizeof(buffer), "%s/.config/%s", str, "alsoft.conf");
+ }
+ if(buffer[0] != 0)
+ {
+ TRACE("Loading config %s...\n", buffer);
f = fopen(buffer, "r");
if(f)
{
@@ -244,8 +274,10 @@ void ReadALConfig(void)
}
}
#endif
+
if((str=getenv("ALSOFT_CONF")) != NULL && *str)
{
+ TRACE("Loading config %s...\n", str);
f = fopen(str, "r");
if(f)
{
@@ -259,51 +291,42 @@ void FreeALConfig(void)
{
unsigned int i;
- for(i = 0;i < cfgCount;i++)
+ for(i = 0;i < cfgBlock.entryCount;i++)
{
- unsigned int j;
- for(j = 0;j < cfgBlocks[i].entryCount;j++)
- {
- free(cfgBlocks[i].entries[j].key);
- free(cfgBlocks[i].entries[j].value);
- }
- free(cfgBlocks[i].entries);
- free(cfgBlocks[i].name);
+ free(cfgBlock.entries[i].key);
+ free(cfgBlock.entries[i].value);
}
- free(cfgBlocks);
- cfgBlocks = NULL;
- cfgCount = 0;
+ free(cfgBlock.entries);
}
const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
{
- unsigned int i, j;
+ unsigned int i;
+ char key[256];
if(!keyName)
return def;
- if(!blockName)
- blockName = "general";
-
- for(i = 0;i < cfgCount;i++)
+ if(blockName && strcasecmp(blockName, "general") != 0)
+ snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
+ else
{
- if(strcasecmp(cfgBlocks[i].name, blockName) != 0)
- continue;
+ strncpy(key, keyName, sizeof(key)-1);
+ key[sizeof(key)-1] = 0;
+ }
- for(j = 0;j < cfgBlocks[i].entryCount;j++)
+ for(i = 0;i < cfgBlock.entryCount;i++)
+ {
+ if(strcasecmp(cfgBlock.entries[i].key, key) == 0)
{
- if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0)
- {
- TRACE("Found %s:%s = \"%s\"\n", blockName, keyName,
- cfgBlocks[i].entries[j].value);
- if(cfgBlocks[i].entries[j].value[0])
- return cfgBlocks[i].entries[j].value;
- return def;
- }
+ TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value);
+ if(cfgBlock.entries[i].value[0])
+ return cfgBlock.entries[i].value;
+ return def;
}
}
- TRACE("Key %s:%s not found\n", blockName, keyName);
+ TRACE("Key %s not found\n", key);
return def;
}
diff --git a/Alc/alcDedicated.c b/Alc/alcDedicated.c
deleted file mode 100644
index 1d2cbc42..00000000
--- a/Alc/alcDedicated.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 2011 by Chris Robinson.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alFilter.h"
-#include "alAuxEffectSlot.h"
-#include "alError.h"
-#include "alu.h"
-
-
-typedef struct ALdedicatedState {
- // Must be first in all effects!
- ALeffectState state;
-
- ALfloat gains[MaxChannels];
-} ALdedicatedState;
-
-
-static ALvoid DedicatedDestroy(ALeffectState *effect)
-{
- ALdedicatedState *state = (ALdedicatedState*)effect;
- free(state);
-}
-
-static ALboolean DedicatedDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
-{
- (void)effect;
- (void)Device;
- return AL_TRUE;
-}
-
-static ALvoid DedicatedUpdate(ALeffectState *effect, ALCdevice *device, const ALeffectslot *Slot)
-{
- ALdedicatedState *state = (ALdedicatedState*)effect;
- ALfloat Gain;
- ALsizei s;
-
- Gain = Slot->Gain * Slot->effect.Dedicated.Gain;
- for(s = 0;s < MaxChannels;s++)
- state->gains[s] = 0.0f;
-
- if(Slot->effect.type == AL_EFFECT_DEDICATED_DIALOGUE)
- ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains);
- else if(Slot->effect.type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
- state->gains[LFE] = Gain;
-}
-
-static ALvoid DedicatedProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
-{
- ALdedicatedState *state = (ALdedicatedState*)effect;
- const ALfloat *gains = state->gains;
- ALuint i, c;
-
- for(c = 0;c < MaxChannels;c++)
- {
- for(i = 0;i < SamplesToDo;i++)
- SamplesOut[c][i] = SamplesIn[i] * gains[c];
- }
-}
-
-ALeffectState *DedicatedCreate(void)
-{
- ALdedicatedState *state;
- ALsizei s;
-
- state = malloc(sizeof(*state));
- if(!state)
- return NULL;
-
- state->state.Destroy = DedicatedDestroy;
- state->state.DeviceUpdate = DedicatedDeviceUpdate;
- state->state.Update = DedicatedUpdate;
- state->state.Process = DedicatedProcess;
-
- for(s = 0;s < MaxChannels;s++)
- state->gains[s] = 0.0f;
-
- return &state->state;
-}
diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c
deleted file mode 100644
index 9ca91747..00000000
--- a/Alc/alcEcho.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 2009 by Chris Robinson.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alFilter.h"
-#include "alAuxEffectSlot.h"
-#include "alError.h"
-#include "alu.h"
-
-
-typedef struct ALechoState {
- // Must be first in all effects!
- ALeffectState state;
-
- ALfloat *SampleBuffer;
- ALuint BufferLength;
-
- // The echo is two tap. The delay is the number of samples from before the
- // current offset
- struct {
- ALuint delay;
- } Tap[2];
- ALuint Offset;
- /* The panning gains for the two taps */
- ALfloat Gain[2][MaxChannels];
-
- ALfloat FeedGain;
-
- FILTER iirFilter;
- ALfloat history[2];
-} ALechoState;
-
-static ALvoid EchoDestroy(ALeffectState *effect)
-{
- ALechoState *state = (ALechoState*)effect;
- if(state)
- {
- free(state->SampleBuffer);
- state->SampleBuffer = NULL;
- free(state);
- }
-}
-
-static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
-{
- ALechoState *state = (ALechoState*)effect;
- ALuint maxlen, i;
-
- // Use the next power of 2 for the buffer length, so the tap offsets can be
- // wrapped using a mask instead of a modulo
- maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
- maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
- maxlen = NextPowerOf2(maxlen);
-
- if(maxlen != state->BufferLength)
- {
- void *temp;
-
- temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
- if(!temp)
- return AL_FALSE;
- state->SampleBuffer = temp;
- state->BufferLength = maxlen;
- }
- for(i = 0;i < state->BufferLength;i++)
- state->SampleBuffer[i] = 0.0f;
-
- return AL_TRUE;
-}
-
-static ALvoid EchoUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot)
-{
- ALechoState *state = (ALechoState*)effect;
- ALuint frequency = Device->Frequency;
- ALfloat lrpan, cw, g, gain;
- ALfloat dirGain;
- ALuint i;
-
- state->Tap[0].delay = fastf2u(Slot->effect.Echo.Delay * frequency) + 1;
- state->Tap[1].delay = fastf2u(Slot->effect.Echo.LRDelay * frequency);
- state->Tap[1].delay += state->Tap[0].delay;
-
- lrpan = Slot->effect.Echo.Spread;
-
- state->FeedGain = Slot->effect.Echo.Feedback;
-
- cw = cosf(F_PI*2.0f * LOWPASSFREQREF / frequency);
- g = 1.0f - Slot->effect.Echo.Damping;
- state->iirFilter.coeff = lpCoeffCalc(g, cw);
-
- gain = Slot->Gain;
- for(i = 0;i < MaxChannels;i++)
- {
- state->Gain[0][i] = 0.0f;
- state->Gain[1][i] = 0.0f;
- }
-
- dirGain = fabsf(lrpan);
-
- /* First tap panning */
- ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]);
-
- /* Second tap panning */
- ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]);
-}
-
-static ALvoid EchoProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
-{
- ALechoState *state = (ALechoState*)effect;
- const ALuint mask = state->BufferLength-1;
- const ALuint tap1 = state->Tap[0].delay;
- const ALuint tap2 = state->Tap[1].delay;
- ALuint offset = state->Offset;
- ALfloat smp;
- ALuint i, k;
-
- for(i = 0;i < SamplesToDo;i++,offset++)
- {
- /* First tap */
- smp = state->SampleBuffer[(offset-tap1) & mask];
- for(k = 0;k < MaxChannels;k++)
- SamplesOut[k][i] += smp * state->Gain[0][k];
-
- /* Second tap */
- smp = state->SampleBuffer[(offset-tap2) & mask];
- for(k = 0;k < MaxChannels;k++)
- SamplesOut[k][i] += smp * state->Gain[1][k];
-
- // Apply damping and feedback gain to the second tap, and mix in the
- // new sample
- smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]);
- state->SampleBuffer[offset&mask] = smp * state->FeedGain;
- }
- state->Offset = offset;
-}
-
-ALeffectState *EchoCreate(void)
-{
- ALechoState *state;
-
- state = malloc(sizeof(*state));
- if(!state)
- return NULL;
-
- state->state.Destroy = EchoDestroy;
- state->state.DeviceUpdate = EchoDeviceUpdate;
- state->state.Update = EchoUpdate;
- state->state.Process = EchoProcess;
-
- state->BufferLength = 0;
- state->SampleBuffer = NULL;
-
- state->Tap[0].delay = 0;
- state->Tap[1].delay = 0;
- state->Offset = 0;
-
- state->iirFilter.coeff = 0.0f;
- state->iirFilter.history[0] = 0.0f;
- state->iirFilter.history[1] = 0.0f;
-
- return &state->state;
-}
diff --git a/Alc/alcModulator.c b/Alc/alcModulator.c
deleted file mode 100644
index de062151..00000000
--- a/Alc/alcModulator.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 2009 by Chris Robinson.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alFilter.h"
-#include "alAuxEffectSlot.h"
-#include "alError.h"
-#include "alu.h"
-
-
-typedef struct ALmodulatorState {
- // Must be first in all effects!
- ALeffectState state;
-
- enum {
- SINUSOID,
- SAWTOOTH,
- SQUARE
- } Waveform;
-
- ALuint index;
- ALuint step;
-
- ALfloat Gain[MaxChannels];
-
- FILTER iirFilter;
- ALfloat history[1];
-} ALmodulatorState;
-
-#define WAVEFORM_FRACBITS 16
-#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
-#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
-
-static __inline ALfloat Sin(ALuint index)
-{
- return sinf(index * (F_PI*2.0f / WAVEFORM_FRACONE));
-}
-
-static __inline ALfloat Saw(ALuint index)
-{
- return index*(2.0f/WAVEFORM_FRACONE) - 1.0f;
-}
-
-static __inline ALfloat Square(ALuint index)
-{
- return ((index>>(WAVEFORM_FRACBITS-1))&1)*2.0f - 1.0f;
-}
-
-
-static __inline ALfloat hpFilter1P(FILTER *iir, ALuint offset, ALfloat input)
-{
- ALfloat *history = &iir->history[offset];
- ALfloat a = iir->coeff;
- ALfloat output = input;
-
- output = output + (history[0]-output)*a;
- history[0] = output;
-
- return input - output;
-}
-
-
-#define DECL_TEMPLATE(func) \
-static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
- const ALfloat *RESTRICT SamplesIn, \
- ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) \
-{ \
- const ALuint step = state->step; \
- ALuint index = state->index; \
- ALfloat samp; \
- ALuint i, k; \
- \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- samp = SamplesIn[i]; \
- \
- index += step; \
- index &= WAVEFORM_FRACMASK; \
- samp *= func(index); \
- \
- samp = hpFilter1P(&state->iirFilter, 0, samp); \
- \
- for(k = 0;k < MaxChannels;k++) \
- SamplesOut[k][i] += state->Gain[k] * samp; \
- } \
- state->index = index; \
-}
-
-DECL_TEMPLATE(Sin)
-DECL_TEMPLATE(Saw)
-DECL_TEMPLATE(Square)
-
-#undef DECL_TEMPLATE
-
-
-static ALvoid ModulatorDestroy(ALeffectState *effect)
-{
- ALmodulatorState *state = (ALmodulatorState*)effect;
- free(state);
-}
-
-static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
-{
- return AL_TRUE;
- (void)effect;
- (void)Device;
-}
-
-static ALvoid ModulatorUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot)
-{
- ALmodulatorState *state = (ALmodulatorState*)effect;
- ALfloat gain, cw, a = 0.0f;
- ALuint index;
-
- if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
- state->Waveform = SINUSOID;
- else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
- state->Waveform = SAWTOOTH;
- else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)
- state->Waveform = SQUARE;
-
- state->step = fastf2u(Slot->effect.Modulator.Frequency*WAVEFORM_FRACONE /
- Device->Frequency);
- if(state->step == 0) state->step = 1;
-
- cw = cosf(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff /
- Device->Frequency);
- a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
- state->iirFilter.coeff = a;
-
- gain = sqrtf(1.0f/Device->NumChan);
- gain *= Slot->Gain;
- for(index = 0;index < MaxChannels;index++)
- state->Gain[index] = 0.0f;
- for(index = 0;index < Device->NumChan;index++)
- {
- enum Channel chan = Device->Speaker2Chan[index];
- state->Gain[chan] = gain;
- }
-}
-
-static ALvoid ModulatorProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
-{
- ALmodulatorState *state = (ALmodulatorState*)effect;
-
- switch(state->Waveform)
- {
- case SINUSOID:
- ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut);
- break;
-
- case SAWTOOTH:
- ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut);
- break;
-
- case SQUARE:
- ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut);
- break;
- }
-}
-
-ALeffectState *ModulatorCreate(void)
-{
- ALmodulatorState *state;
-
- state = malloc(sizeof(*state));
- if(!state)
- return NULL;
-
- state->state.Destroy = ModulatorDestroy;
- state->state.DeviceUpdate = ModulatorDeviceUpdate;
- state->state.Update = ModulatorUpdate;
- state->state.Process = ModulatorProcess;
-
- state->index = 0;
- state->step = 1;
-
- state->iirFilter.coeff = 0.0f;
- state->iirFilter.history[0] = 0.0f;
-
- return &state->state;
-}
diff --git a/Alc/alcRing.c b/Alc/alcRing.c
index 2d9d5069..f831860f 100644
--- a/Alc/alcRing.c
+++ b/Alc/alcRing.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include "alMain.h"
+#include "compat.h"
struct RingBuffer {
diff --git a/Alc/alcThread.c b/Alc/alcThread.c
deleted file mode 100644
index c2f38031..00000000
--- a/Alc/alcThread.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 1999-2007 by authors.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alThunk.h"
-
-#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */
-
-#ifdef _WIN32
-
-typedef struct {
- ALuint (*func)(ALvoid*);
- ALvoid *ptr;
- HANDLE thread;
-} ThreadInfo;
-
-static DWORD CALLBACK StarterFunc(void *ptr)
-{
- ThreadInfo *inf = (ThreadInfo*)ptr;
- ALint ret;
-
- ret = inf->func(inf->ptr);
- ExitThread((DWORD)ret);
-
- return (DWORD)ret;
-}
-
-ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
-{
- DWORD dummy;
- ThreadInfo *inf = malloc(sizeof(ThreadInfo));
- if(!inf) return 0;
-
- inf->func = func;
- inf->ptr = ptr;
-
- inf->thread = CreateThread(NULL, THREAD_STACK_SIZE, StarterFunc, inf, 0, &dummy);
- if(!inf->thread)
- {
- free(inf);
- return NULL;
- }
-
- return inf;
-}
-
-ALuint StopThread(ALvoid *thread)
-{
- ThreadInfo *inf = thread;
- DWORD ret = 0;
-
- WaitForSingleObject(inf->thread, INFINITE);
- GetExitCodeThread(inf->thread, &ret);
- CloseHandle(inf->thread);
-
- free(inf);
-
- return (ALuint)ret;
-}
-
-#else
-
-#include <pthread.h>
-
-typedef struct {
- ALuint (*func)(ALvoid*);
- ALvoid *ptr;
- ALuint ret;
- pthread_t thread;
-} ThreadInfo;
-
-static void *StarterFunc(void *ptr)
-{
- ThreadInfo *inf = (ThreadInfo*)ptr;
- inf->ret = inf->func(inf->ptr);
- return NULL;
-}
-
-ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
-{
- pthread_attr_t attr;
- ThreadInfo *inf = malloc(sizeof(ThreadInfo));
- if(!inf) return NULL;
-
- if(pthread_attr_init(&attr) != 0)
- {
- free(inf);
- return NULL;
- }
- if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0)
- {
- pthread_attr_destroy(&attr);
- free(inf);
- return NULL;
- }
-
- inf->func = func;
- inf->ptr = ptr;
- if(pthread_create(&inf->thread, &attr, StarterFunc, inf) != 0)
- {
- pthread_attr_destroy(&attr);
- free(inf);
- return NULL;
- }
- pthread_attr_destroy(&attr);
-
- return inf;
-}
-
-ALuint StopThread(ALvoid *thread)
-{
- ThreadInfo *inf = thread;
- ALuint ret;
-
- pthread_join(inf->thread, NULL);
- ret = inf->ret;
-
- free(inf);
-
- return ret;
-}
-
-#endif
diff --git a/Alc/atomic.h b/Alc/atomic.h
new file mode 100644
index 00000000..1dd8f9dc
--- /dev/null
+++ b/Alc/atomic.h
@@ -0,0 +1,180 @@
+#ifndef AL_ATOMIC_H
+#define AL_ATOMIC_H
+
+
+typedef void *volatile XchgPtr;
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
+typedef unsigned int RefCount;
+inline RefCount IncrementRef(volatile RefCount *ptr)
+{ return __sync_add_and_fetch(ptr, 1); }
+inline RefCount DecrementRef(volatile RefCount *ptr)
+{ return __sync_sub_and_fetch(ptr, 1); }
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{
+ return __sync_lock_test_and_set(ptr, newval);
+}
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{
+ return __sync_lock_test_and_set(ptr, newval);
+}
+inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{
+ return __sync_bool_compare_and_swap(ptr, oldval, newval);
+}
+inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{
+ return __sync_bool_compare_and_swap(ptr, oldval, newval);
+}
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+inline unsigned int xaddl(volatile unsigned int *dest, int incr)
+{
+ unsigned int ret;
+ __asm__ __volatile__("lock; xaddl %0,(%1)"
+ : "=r" (ret)
+ : "r" (dest), "0" (incr)
+ : "memory");
+ return ret;
+}
+
+typedef unsigned int RefCount;
+inline RefCount IncrementRef(volatile RefCount *ptr)
+{ return xaddl(ptr, 1)+1; }
+inline RefCount DecrementRef(volatile RefCount *ptr)
+{ return xaddl(ptr, -1)-1; }
+
+inline int ExchangeInt(volatile int *dest, int newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; xchgl %0,(%1)"
+ : "=r" (ret)
+ : "r" (dest), "0" (newval)
+ : "memory");
+ return ret;
+}
+
+inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
+ : "=a" (ret)
+ : "r" (dest), "r" (newval), "0" (oldval)
+ : "memory");
+ return ret == oldval;
+}
+
+inline void *ExchangePtr(XchgPtr *dest, void *newval)
+{
+ void *ret;
+ __asm__ __volatile__(
+#ifdef __i386__
+ "lock; xchgl %0,(%1)"
+#else
+ "lock; xchgq %0,(%1)"
+#endif
+ : "=r" (ret)
+ : "r" (dest), "0" (newval)
+ : "memory"
+ );
+ return ret;
+}
+
+inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
+{
+ void *ret;
+ __asm__ __volatile__(
+#ifdef __i386__
+ "lock; cmpxchgl %2,(%1)"
+#else
+ "lock; cmpxchgq %2,(%1)"
+#endif
+ : "=a" (ret)
+ : "r" (dest), "r" (newval), "0" (oldval)
+ : "memory"
+ );
+ return ret == oldval;
+}
+
+#elif defined(_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef LONG RefCount;
+inline RefCount IncrementRef(volatile RefCount *ptr)
+{ return InterlockedIncrement(ptr); }
+inline RefCount DecrementRef(volatile RefCount *ptr)
+{ return InterlockedDecrement(ptr); }
+
+extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1];
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{
+ union {
+ volatile int *i;
+ volatile LONG *l;
+ } u = { ptr };
+ return InterlockedExchange(u.l, newval);
+}
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{
+ return InterlockedExchangePointer(ptr, newval);
+}
+inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{
+ union {
+ volatile int *i;
+ volatile LONG *l;
+ } u = { ptr };
+ return InterlockedCompareExchange(u.l, newval, oldval) == oldval;
+}
+inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{
+ return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval;
+}
+
+#elif defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+typedef int32_t RefCount;
+inline RefCount IncrementRef(volatile RefCount *ptr)
+{ return OSAtomicIncrement32Barrier(ptr); }
+inline RefCount DecrementRef(volatile RefCount *ptr)
+{ return OSAtomicDecrement32Barrier(ptr); }
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{
+ /* Really? No regular old atomic swap? */
+ int oldval;
+ do {
+ oldval = *ptr;
+ } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr));
+ return oldval;
+}
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{
+ void *oldval;
+ do {
+ oldval = *ptr;
+ } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr));
+ return oldval;
+}
+inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{
+ return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr);
+}
+inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{
+ return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr);
+}
+
+#else
+#error "No atomic functions available on this platform!"
+typedef ALuint RefCount;
+#endif
+
+#endif /* AL_ATOMIC_H */
diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c
index 5ff6307f..874b31c3 100644
--- a/Alc/backends/alsa.c
+++ b/Alc/backends/alsa.c
@@ -26,6 +26,10 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
#include <alsa/asoundlib.h>
@@ -34,80 +38,83 @@ static const ALCchar alsaDevice[] = "ALSA Default";
#ifdef HAVE_DYNLOAD
+#define ALSA_FUNCS(MAGIC) \
+ MAGIC(snd_strerror); \
+ MAGIC(snd_pcm_open); \
+ MAGIC(snd_pcm_close); \
+ MAGIC(snd_pcm_nonblock); \
+ MAGIC(snd_pcm_frames_to_bytes); \
+ MAGIC(snd_pcm_bytes_to_frames); \
+ MAGIC(snd_pcm_hw_params_malloc); \
+ MAGIC(snd_pcm_hw_params_free); \
+ MAGIC(snd_pcm_hw_params_any); \
+ MAGIC(snd_pcm_hw_params_current); \
+ MAGIC(snd_pcm_hw_params_set_access); \
+ MAGIC(snd_pcm_hw_params_set_format); \
+ MAGIC(snd_pcm_hw_params_set_channels); \
+ MAGIC(snd_pcm_hw_params_set_periods_near); \
+ MAGIC(snd_pcm_hw_params_set_rate_near); \
+ MAGIC(snd_pcm_hw_params_set_rate); \
+ MAGIC(snd_pcm_hw_params_set_rate_resample); \
+ MAGIC(snd_pcm_hw_params_set_buffer_time_near); \
+ MAGIC(snd_pcm_hw_params_set_period_time_near); \
+ MAGIC(snd_pcm_hw_params_set_buffer_size_near); \
+ MAGIC(snd_pcm_hw_params_set_period_size_near); \
+ MAGIC(snd_pcm_hw_params_set_buffer_size_min); \
+ MAGIC(snd_pcm_hw_params_get_buffer_time_min); \
+ MAGIC(snd_pcm_hw_params_get_buffer_time_max); \
+ MAGIC(snd_pcm_hw_params_get_period_time_min); \
+ MAGIC(snd_pcm_hw_params_get_period_time_max); \
+ MAGIC(snd_pcm_hw_params_get_buffer_size); \
+ MAGIC(snd_pcm_hw_params_get_period_size); \
+ MAGIC(snd_pcm_hw_params_get_access); \
+ MAGIC(snd_pcm_hw_params_get_periods); \
+ MAGIC(snd_pcm_hw_params_test_format); \
+ MAGIC(snd_pcm_hw_params_test_channels); \
+ MAGIC(snd_pcm_hw_params); \
+ MAGIC(snd_pcm_sw_params_malloc); \
+ MAGIC(snd_pcm_sw_params_current); \
+ MAGIC(snd_pcm_sw_params_set_avail_min); \
+ MAGIC(snd_pcm_sw_params_set_stop_threshold); \
+ MAGIC(snd_pcm_sw_params); \
+ MAGIC(snd_pcm_sw_params_free); \
+ MAGIC(snd_pcm_prepare); \
+ MAGIC(snd_pcm_start); \
+ MAGIC(snd_pcm_resume); \
+ MAGIC(snd_pcm_reset); \
+ MAGIC(snd_pcm_wait); \
+ MAGIC(snd_pcm_delay); \
+ MAGIC(snd_pcm_state); \
+ MAGIC(snd_pcm_avail_update); \
+ MAGIC(snd_pcm_areas_silence); \
+ MAGIC(snd_pcm_mmap_begin); \
+ MAGIC(snd_pcm_mmap_commit); \
+ MAGIC(snd_pcm_readi); \
+ MAGIC(snd_pcm_writei); \
+ MAGIC(snd_pcm_drain); \
+ MAGIC(snd_pcm_drop); \
+ MAGIC(snd_pcm_recover); \
+ MAGIC(snd_pcm_info_malloc); \
+ MAGIC(snd_pcm_info_free); \
+ MAGIC(snd_pcm_info_set_device); \
+ MAGIC(snd_pcm_info_set_subdevice); \
+ MAGIC(snd_pcm_info_set_stream); \
+ MAGIC(snd_pcm_info_get_name); \
+ MAGIC(snd_ctl_pcm_next_device); \
+ MAGIC(snd_ctl_pcm_info); \
+ MAGIC(snd_ctl_open); \
+ MAGIC(snd_ctl_close); \
+ MAGIC(snd_ctl_card_info_malloc); \
+ MAGIC(snd_ctl_card_info_free); \
+ MAGIC(snd_ctl_card_info); \
+ MAGIC(snd_ctl_card_info_get_name); \
+ MAGIC(snd_ctl_card_info_get_id); \
+ MAGIC(snd_card_next); \
+ MAGIC(snd_config_update_free_global)
+
static void *alsa_handle;
-#define MAKE_FUNC(f) static typeof(f) * p##f
-MAKE_FUNC(snd_strerror);
-MAKE_FUNC(snd_pcm_open);
-MAKE_FUNC(snd_pcm_close);
-MAKE_FUNC(snd_pcm_nonblock);
-MAKE_FUNC(snd_pcm_frames_to_bytes);
-MAKE_FUNC(snd_pcm_bytes_to_frames);
-MAKE_FUNC(snd_pcm_hw_params_malloc);
-MAKE_FUNC(snd_pcm_hw_params_free);
-MAKE_FUNC(snd_pcm_hw_params_any);
-MAKE_FUNC(snd_pcm_hw_params_current);
-MAKE_FUNC(snd_pcm_hw_params_set_access);
-MAKE_FUNC(snd_pcm_hw_params_set_format);
-MAKE_FUNC(snd_pcm_hw_params_set_channels);
-MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
-MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
-MAKE_FUNC(snd_pcm_hw_params_set_rate);
-MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
-MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
-MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
-MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
-MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
-MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
-MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_min);
-MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_max);
-MAKE_FUNC(snd_pcm_hw_params_get_period_time_min);
-MAKE_FUNC(snd_pcm_hw_params_get_period_time_max);
-MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
-MAKE_FUNC(snd_pcm_hw_params_get_period_size);
-MAKE_FUNC(snd_pcm_hw_params_get_access);
-MAKE_FUNC(snd_pcm_hw_params_get_periods);
-MAKE_FUNC(snd_pcm_hw_params_test_format);
-MAKE_FUNC(snd_pcm_hw_params_test_channels);
-MAKE_FUNC(snd_pcm_hw_params);
-MAKE_FUNC(snd_pcm_sw_params_malloc);
-MAKE_FUNC(snd_pcm_sw_params_current);
-MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
-MAKE_FUNC(snd_pcm_sw_params_set_stop_threshold);
-MAKE_FUNC(snd_pcm_sw_params);
-MAKE_FUNC(snd_pcm_sw_params_free);
-MAKE_FUNC(snd_pcm_prepare);
-MAKE_FUNC(snd_pcm_start);
-MAKE_FUNC(snd_pcm_resume);
-MAKE_FUNC(snd_pcm_reset);
-MAKE_FUNC(snd_pcm_wait);
-MAKE_FUNC(snd_pcm_delay);
-MAKE_FUNC(snd_pcm_state);
-MAKE_FUNC(snd_pcm_avail_update);
-MAKE_FUNC(snd_pcm_areas_silence);
-MAKE_FUNC(snd_pcm_mmap_begin);
-MAKE_FUNC(snd_pcm_mmap_commit);
-MAKE_FUNC(snd_pcm_readi);
-MAKE_FUNC(snd_pcm_writei);
-MAKE_FUNC(snd_pcm_drain);
-MAKE_FUNC(snd_pcm_drop);
-MAKE_FUNC(snd_pcm_recover);
-MAKE_FUNC(snd_pcm_info_malloc);
-MAKE_FUNC(snd_pcm_info_free);
-MAKE_FUNC(snd_pcm_info_set_device);
-MAKE_FUNC(snd_pcm_info_set_subdevice);
-MAKE_FUNC(snd_pcm_info_set_stream);
-MAKE_FUNC(snd_pcm_info_get_name);
-MAKE_FUNC(snd_ctl_pcm_next_device);
-MAKE_FUNC(snd_ctl_pcm_info);
-MAKE_FUNC(snd_ctl_open);
-MAKE_FUNC(snd_ctl_close);
-MAKE_FUNC(snd_ctl_card_info_malloc);
-MAKE_FUNC(snd_ctl_card_info_free);
-MAKE_FUNC(snd_ctl_card_info);
-MAKE_FUNC(snd_ctl_card_info_get_name);
-MAKE_FUNC(snd_ctl_card_info_get_id);
-MAKE_FUNC(snd_card_next);
-MAKE_FUNC(snd_config_update_free_global);
+#define MAKE_FUNC(f) static __typeof(f) * p##f
+ALSA_FUNCS(MAKE_FUNC);
#undef MAKE_FUNC
#define snd_strerror psnd_strerror
@@ -187,6 +194,8 @@ MAKE_FUNC(snd_config_update_free_global);
static ALCboolean alsa_load(void)
{
+ ALCboolean error = ALC_FALSE;
+
#ifdef HAVE_DYNLOAD
if(!alsa_handle)
{
@@ -194,107 +203,28 @@ static ALCboolean alsa_load(void)
if(!alsa_handle)
return ALC_FALSE;
+ error = ALC_FALSE;
#define LOAD_FUNC(f) do { \
p##f = GetSymbol(alsa_handle, #f); \
if(p##f == NULL) { \
- CloseLib(alsa_handle); \
- alsa_handle = NULL; \
- return ALC_FALSE; \
+ error = ALC_TRUE; \
} \
} while(0)
- LOAD_FUNC(snd_strerror);
- LOAD_FUNC(snd_pcm_open);
- LOAD_FUNC(snd_pcm_close);
- LOAD_FUNC(snd_pcm_nonblock);
- LOAD_FUNC(snd_pcm_frames_to_bytes);
- LOAD_FUNC(snd_pcm_bytes_to_frames);
- LOAD_FUNC(snd_pcm_hw_params_malloc);
- LOAD_FUNC(snd_pcm_hw_params_free);
- LOAD_FUNC(snd_pcm_hw_params_any);
- LOAD_FUNC(snd_pcm_hw_params_current);
- LOAD_FUNC(snd_pcm_hw_params_set_access);
- LOAD_FUNC(snd_pcm_hw_params_set_format);
- LOAD_FUNC(snd_pcm_hw_params_set_channels);
- LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
- LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
- LOAD_FUNC(snd_pcm_hw_params_set_rate);
- LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
- LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
- LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
- LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
- LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
- LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
- LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_min);
- LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_max);
- LOAD_FUNC(snd_pcm_hw_params_get_period_time_min);
- LOAD_FUNC(snd_pcm_hw_params_get_period_time_max);
- LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
- LOAD_FUNC(snd_pcm_hw_params_get_period_size);
- LOAD_FUNC(snd_pcm_hw_params_get_access);
- LOAD_FUNC(snd_pcm_hw_params_get_periods);
- LOAD_FUNC(snd_pcm_hw_params_test_format);
- LOAD_FUNC(snd_pcm_hw_params_test_channels);
- LOAD_FUNC(snd_pcm_hw_params);
- LOAD_FUNC(snd_pcm_sw_params_malloc);
- LOAD_FUNC(snd_pcm_sw_params_current);
- LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
- LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
- LOAD_FUNC(snd_pcm_sw_params);
- LOAD_FUNC(snd_pcm_sw_params_free);
- LOAD_FUNC(snd_pcm_prepare);
- LOAD_FUNC(snd_pcm_start);
- LOAD_FUNC(snd_pcm_resume);
- LOAD_FUNC(snd_pcm_reset);
- LOAD_FUNC(snd_pcm_wait);
- LOAD_FUNC(snd_pcm_delay);
- LOAD_FUNC(snd_pcm_state);
- LOAD_FUNC(snd_pcm_avail_update);
- LOAD_FUNC(snd_pcm_areas_silence);
- LOAD_FUNC(snd_pcm_mmap_begin);
- LOAD_FUNC(snd_pcm_mmap_commit);
- LOAD_FUNC(snd_pcm_readi);
- LOAD_FUNC(snd_pcm_writei);
- LOAD_FUNC(snd_pcm_drain);
- LOAD_FUNC(snd_pcm_drop);
- LOAD_FUNC(snd_pcm_recover);
- LOAD_FUNC(snd_pcm_info_malloc);
- LOAD_FUNC(snd_pcm_info_free);
- LOAD_FUNC(snd_pcm_info_set_device);
- LOAD_FUNC(snd_pcm_info_set_subdevice);
- LOAD_FUNC(snd_pcm_info_set_stream);
- LOAD_FUNC(snd_pcm_info_get_name);
- LOAD_FUNC(snd_ctl_pcm_next_device);
- LOAD_FUNC(snd_ctl_pcm_info);
- LOAD_FUNC(snd_ctl_open);
- LOAD_FUNC(snd_ctl_close);
- LOAD_FUNC(snd_ctl_card_info_malloc);
- LOAD_FUNC(snd_ctl_card_info_free);
- LOAD_FUNC(snd_ctl_card_info);
- LOAD_FUNC(snd_ctl_card_info_get_name);
- LOAD_FUNC(snd_ctl_card_info_get_id);
- LOAD_FUNC(snd_card_next);
- LOAD_FUNC(snd_config_update_free_global);
+ ALSA_FUNCS(LOAD_FUNC);
#undef LOAD_FUNC
+
+ if(error)
+ {
+ CloseLib(alsa_handle);
+ alsa_handle = NULL;
+ return ALC_FALSE;
+ }
}
#endif
- return ALC_TRUE;
-}
-
-
-typedef struct {
- snd_pcm_t *pcmHandle;
-
- ALvoid *buffer;
- ALsizei size;
-
- ALboolean doCapture;
- RingBuffer *ring;
- snd_pcm_sframes_t last_avail;
+ return !error;
+}
- volatile int killNow;
- ALvoid *thread;
-} alsa_data;
typedef struct {
ALCchar *name;
@@ -451,10 +381,46 @@ static int verify_state(snd_pcm_t *handle)
}
-static ALuint ALSAProc(ALvoid *ptr)
+typedef struct ALCplaybackAlsa {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ snd_pcm_t *pcmHandle;
+
+ ALvoid *buffer;
+ ALsizei size;
+
+ volatile int killNow;
+ althread_t thread;
+} ALCplaybackAlsa;
+DECLARE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
+
+static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr);
+static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr);
+
+static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
+static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
+static void ALCplaybackAlsa_close(ALCplaybackAlsa *self);
+static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
+static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
+static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
+static DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
+
+
+static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
+}
+
+
+static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const snd_pcm_channel_area_t *areas = NULL;
snd_pcm_uframes_t update_size, num_updates;
snd_pcm_sframes_t avail, commitres;
@@ -463,22 +429,23 @@ static ALuint ALSAProc(ALvoid *ptr)
int err;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
- update_size = Device->UpdateSize;
- num_updates = Device->NumUpdates;
- while(!data->killNow)
+ update_size = device->UpdateSize;
+ num_updates = device->NumUpdates;
+ while(!self->killNow)
{
- int state = verify_state(data->pcmHandle);
+ int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCplaybackAlsa_lock(self);
+ aluHandleDisconnect(device);
+ ALCplaybackAlsa_unlock(self);
break;
}
- avail = snd_pcm_avail_update(data->pcmHandle);
+ avail = snd_pcm_avail_update(self->pcmHandle);
if(avail < 0)
{
ERR("available update failed: %s\n", snd_strerror(avail));
@@ -488,7 +455,7 @@ static ALuint ALSAProc(ALvoid *ptr)
if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
{
WARN("available samples exceeds the buffer size\n");
- snd_pcm_reset(data->pcmHandle);
+ snd_pcm_reset(self->pcmHandle);
continue;
}
@@ -497,26 +464,26 @@ static ALuint ALSAProc(ALvoid *ptr)
{
if(state != SND_PCM_STATE_RUNNING)
{
- err = snd_pcm_start(data->pcmHandle);
+ err = snd_pcm_start(self->pcmHandle);
if(err < 0)
{
ERR("start failed: %s\n", snd_strerror(err));
continue;
}
}
- if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
+ if(snd_pcm_wait(self->pcmHandle, 1000) == 0)
ERR("Wait timeout... buffer size too low?\n");
continue;
}
avail -= avail%update_size;
// it is possible that contiguous areas are smaller, thus we use a loop
- ALCdevice_Lock(Device);
+ ALCplaybackAlsa_lock(self);
while(avail > 0)
{
frames = avail;
- err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
+ err = snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames);
if(err < 0)
{
ERR("mmap begin error: %s\n", snd_strerror(err));
@@ -524,9 +491,9 @@ static ALuint ALSAProc(ALvoid *ptr)
}
WritePtr = (char*)areas->addr + (offset * areas->step / 8);
- aluMixData(Device, WritePtr, frames);
+ aluMixData(device, WritePtr, frames);
- commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
+ commitres = snd_pcm_mmap_commit(self->pcmHandle, offset, frames);
if(commitres < 0 || (commitres-frames) != 0)
{
ERR("mmap commit error: %s\n",
@@ -536,38 +503,39 @@ static ALuint ALSAProc(ALvoid *ptr)
avail -= frames;
}
- ALCdevice_Unlock(Device);
+ ALCplaybackAlsa_unlock(self);
}
return 0;
}
-static ALuint ALSANoMMapProc(ALvoid *ptr)
+static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_uframes_t update_size, num_updates;
snd_pcm_sframes_t avail;
char *WritePtr;
int err;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
- update_size = Device->UpdateSize;
- num_updates = Device->NumUpdates;
- while(!data->killNow)
+ update_size = device->UpdateSize;
+ num_updates = device->NumUpdates;
+ while(!self->killNow)
{
- int state = verify_state(data->pcmHandle);
+ int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCplaybackAlsa_lock(self);
+ aluHandleDisconnect(device);
+ ALCplaybackAlsa_unlock(self);
break;
}
- avail = snd_pcm_avail_update(data->pcmHandle);
+ avail = snd_pcm_avail_update(self->pcmHandle);
if(avail < 0)
{
ERR("available update failed: %s\n", snd_strerror(avail));
@@ -577,7 +545,7 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
if((snd_pcm_uframes_t)avail > update_size*num_updates)
{
WARN("available samples exceeds the buffer size\n");
- snd_pcm_reset(data->pcmHandle);
+ snd_pcm_reset(self->pcmHandle);
continue;
}
@@ -585,26 +553,26 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
{
if(state != SND_PCM_STATE_RUNNING)
{
- err = snd_pcm_start(data->pcmHandle);
+ err = snd_pcm_start(self->pcmHandle);
if(err < 0)
{
ERR("start failed: %s\n", snd_strerror(err));
continue;
}
}
- if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
+ if(snd_pcm_wait(self->pcmHandle, 1000) == 0)
ERR("Wait timeout... buffer size too low?\n");
continue;
}
- ALCdevice_Lock(Device);
- WritePtr = data->buffer;
- avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
- aluMixData(Device, WritePtr, avail);
+ ALCplaybackAlsa_lock(self);
+ WritePtr = self->buffer;
+ avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
+ aluMixData(device, WritePtr, avail);
while(avail > 0)
{
- int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
+ int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail);
switch (ret)
{
case -EAGAIN:
@@ -612,38 +580,39 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
case -ESTRPIPE:
case -EPIPE:
case -EINTR:
- ret = snd_pcm_recover(data->pcmHandle, ret, 1);
+ ret = snd_pcm_recover(self->pcmHandle, ret, 1);
if(ret < 0)
avail = 0;
break;
default:
if (ret >= 0)
{
- WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
+ WritePtr += snd_pcm_frames_to_bytes(self->pcmHandle, ret);
avail -= ret;
}
break;
}
if (ret < 0)
{
- ret = snd_pcm_prepare(data->pcmHandle);
+ ret = snd_pcm_prepare(self->pcmHandle);
if(ret < 0)
break;
}
}
- ALCdevice_Unlock(Device);
+ ALCplaybackAlsa_unlock(self);
}
return 0;
}
-static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const char *driver = NULL;
- alsa_data *data;
int err;
- if(deviceName)
+ if(name)
{
size_t idx;
@@ -652,7 +621,7 @@ static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
for(idx = 0;idx < numDevNames;idx++)
{
- if(strcmp(deviceName, allDevNameMap[idx].name) == 0)
+ if(strcmp(name, allDevNameMap[idx].name) == 0)
{
driver = allDevNameMap[idx].device;
break;
@@ -663,16 +632,13 @@ static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
}
else
{
- deviceName = alsaDevice;
+ name = alsaDevice;
driver = GetConfigValue("alsa", "device", "default");
}
- data = (alsa_data*)calloc(1, sizeof(alsa_data));
-
- err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if(err < 0)
{
- free(data);
ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
return ALC_OUT_OF_MEMORY;
}
@@ -680,23 +646,19 @@ static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
- device->DeviceName = strdup(deviceName);
- device->ExtraData = data;
+ device->DeviceName = strdup(name);
+
return ALC_NO_ERROR;
}
-static void alsa_close_playback(ALCdevice *device)
+static void ALCplaybackAlsa_close(ALCplaybackAlsa *self)
{
- alsa_data *data = (alsa_data*)device->ExtraData;
-
- snd_pcm_close(data->pcmHandle);
- free(data);
- device->ExtraData = NULL;
+ snd_pcm_close(self->pcmHandle);
}
-static ALCboolean alsa_reset_playback(ALCdevice *device)
+static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
{
- alsa_data *data = (alsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_uframes_t periodSizeInFrames;
unsigned int periodLen, bufferLen;
snd_pcm_sw_params_t *sp = NULL;
@@ -743,15 +705,15 @@ static ALCboolean alsa_reset_playback(ALCdevice *device)
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
+ CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp));
/* set interleaved access */
- if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
+ if(!allowmmap || snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
{
/* No mmap */
- CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
+ CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
}
/* test and set format (implicitly sets sample bits) */
- if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
+ if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) < 0)
{
static const struct {
snd_pcm_format_t format;
@@ -770,16 +732,16 @@ static ALCboolean alsa_reset_playback(ALCdevice *device)
for(k = 0;k < COUNTOF(formatlist);k++)
{
format = formatlist[k].format;
- if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
+ if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0)
{
device->FmtType = formatlist[k].fmttype;
break;
}
}
}
- CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
+ CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
/* test and set channels (implicitly sets frame bits) */
- if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
+ if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
{
static const enum DevFmtChannels channellist[] = {
DevFmtStereo,
@@ -792,26 +754,26 @@ static ALCboolean alsa_reset_playback(ALCdevice *device)
for(k = 0;k < COUNTOF(channellist);k++)
{
- if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
+ if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
{
device->FmtChans = channellist[k];
break;
}
}
}
- CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
+ CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
/* set rate (implicitly constrains period/buffer parameters) */
- if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
+ if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
ERR("Failed to disable ALSA resampler\n");
- CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
+ CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
/* set buffer time (implicitly constrains period/buffer parameters) */
- if(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL) < 0)
+ if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
/* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
- if(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL) < 0)
+ if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, NULL)) < 0)
ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
/* install and prepare hardware configuration */
- CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
+ CHECK(snd_pcm_hw_params(self->pcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_access(hp, &access));
CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
@@ -821,10 +783,10 @@ static ALCboolean alsa_reset_playback(ALCdevice *device)
hp = NULL;
snd_pcm_sw_params_malloc(&sp);
- CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
- CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
- CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
- CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
+ CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp));
+ CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames));
+ CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods));
+ CHECK(snd_pcm_sw_params(self->pcmHandle, sp));
#undef CHECK
snd_pcm_sw_params_free(sp);
sp = NULL;
@@ -844,9 +806,10 @@ error:
return ALC_FALSE;
}
-static ALCboolean alsa_start_playback(ALCdevice *device)
+static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
{
- alsa_data *data = (alsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALuint (*thread_func)(ALvoid*) = NULL;
snd_pcm_hw_params_t *hp = NULL;
snd_pcm_access_t access;
const char *funcerr;
@@ -854,39 +817,39 @@ static ALCboolean alsa_start_playback(ALCdevice *device)
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp));
+ CHECK(snd_pcm_hw_params_current(self->pcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_access(hp, &access));
#undef CHECK
snd_pcm_hw_params_free(hp);
hp = NULL;
- data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
+ self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
- data->buffer = malloc(data->size);
- if(!data->buffer)
+ self->buffer = malloc(self->size);
+ if(!self->buffer)
{
ERR("buffer malloc failed\n");
return ALC_FALSE;
}
- data->thread = StartThread(ALSANoMMapProc, device);
+ thread_func = ALCplaybackAlsa_mixerNoMMapProc;
}
else
{
- err = snd_pcm_prepare(data->pcmHandle);
+ err = snd_pcm_prepare(self->pcmHandle);
if(err < 0)
{
ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err));
return ALC_FALSE;
}
- data->thread = StartThread(ALSAProc, device);
+ thread_func = ALCplaybackAlsa_mixerProc;
}
- if(data->thread == NULL)
+ if(!StartThread(&self->thread, thread_func, self))
{
ERR("Could not create playback thread\n");
- free(data->buffer);
- data->buffer = NULL;
+ free(self->buffer);
+ self->buffer = NULL;
return ALC_FALSE;
}
@@ -898,24 +861,80 @@ error:
return ALC_FALSE;
}
-static void alsa_stop_playback(ALCdevice *device)
+static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
{
- alsa_data *data = (alsa_data*)device->ExtraData;
+ if(self->thread)
+ {
+ self->killNow = 1;
+ StopThread(self->thread);
+ self->thread = NULL;
+ }
+ self->killNow = 0;
+ free(self->buffer);
+ self->buffer = NULL;
+}
- if(data->thread)
+static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ snd_pcm_sframes_t delay = 0;
+ int err;
+
+ if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
{
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
+ ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
+ return 0;
}
- data->killNow = 0;
- free(data->buffer);
- data->buffer = NULL;
+ return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
+}
+
+
+static void ALCplaybackAlsa_Delete(ALCplaybackAlsa *self)
+{
+ free(self);
+}
+
+DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
+
+
+typedef struct ALCcaptureAlsa {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ snd_pcm_t *pcmHandle;
+
+ ALvoid *buffer;
+ ALsizei size;
+
+ ALboolean doCapture;
+ RingBuffer *ring;
+
+ snd_pcm_sframes_t last_avail;
+} ALCcaptureAlsa;
+DECLARE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
+
+static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
+static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
+static void ALCcaptureAlsa_close(ALCcaptureAlsa *self);
+static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
+static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
+static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
+static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
+
+
+static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
}
-static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
+static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const char *driver = NULL;
snd_pcm_hw_params_t *hp;
snd_pcm_uframes_t bufferSizeInFrames;
@@ -923,10 +942,9 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
ALboolean needring = AL_FALSE;
snd_pcm_format_t format;
const char *funcerr;
- alsa_data *data;
int err;
- if(deviceName)
+ if(name)
{
size_t idx;
@@ -935,7 +953,7 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
for(idx = 0;idx < numCaptureDevNames;idx++)
{
- if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
+ if(strcmp(name, allCaptureDevNameMap[idx].name) == 0)
{
driver = allCaptureDevNameMap[idx].device;
break;
@@ -946,17 +964,14 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
}
else
{
- deviceName = alsaDevice;
+ name = alsaDevice;
driver = GetConfigValue("alsa", "capture", "default");
}
- data = (alsa_data*)calloc(1, sizeof(alsa_data));
-
- err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if(err < 0)
{
ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
- free(data);
return ALC_INVALID_VALUE;
}
@@ -964,7 +979,7 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
snd_config_update_free_global();
format = -1;
- switch(Device->FmtType)
+ switch(device->FmtType)
{
case DevFmtByte:
format = SND_PCM_FORMAT_S8;
@@ -990,32 +1005,32 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
}
funcerr = NULL;
- bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates,
- 100*Device->Frequency/1000);
- periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000);
+ bufferSizeInFrames = maxu(device->UpdateSize*device->NumUpdates,
+ 100*device->Frequency/1000);
+ periodSizeInFrames = minu(bufferSizeInFrames, 25*device->Frequency/1000);
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
+ CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp));
/* set interleaved access */
- CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
+ CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
/* set format (implicitly sets sample bits) */
- CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
+ CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
/* set channels (implicitly sets frame bits) */
- CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans)));
+ CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
/* set rate (implicitly constrains period/buffer parameters) */
- CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0));
+ CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0));
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
- if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0)
+ if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0)
{
TRACE("Buffer too large, using intermediate ring buffer\n");
needring = AL_TRUE;
- CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames));
+ CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames));
}
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
- CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL));
+ CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, NULL));
/* install and prepare hardware configuration */
- CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
+ CHECK(snd_pcm_hw_params(self->pcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
#undef CHECK
@@ -1024,26 +1039,25 @@ static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName)
if(needring)
{
- data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType),
- Device->UpdateSize*Device->NumUpdates);
- if(!data->ring)
+ self->ring = CreateRingBuffer(FrameSizeFromDevFmt(device->FmtChans, device->FmtType),
+ device->UpdateSize*device->NumUpdates);
+ if(!self->ring)
{
ERR("ring buffer create failed\n");
goto error2;
}
- data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
- data->buffer = malloc(data->size);
- if(!data->buffer)
+ self->size = snd_pcm_frames_to_bytes(self->pcmHandle, periodSizeInFrames);
+ self->buffer = malloc(self->size);
+ if(!self->buffer)
{
ERR("buffer malloc failed\n");
goto error2;
}
}
- Device->DeviceName = strdup(deviceName);
+ device->DeviceName = strdup(name);
- Device->ExtraData = data;
return ALC_NO_ERROR;
error:
@@ -1051,227 +1065,221 @@ error:
if(hp) snd_pcm_hw_params_free(hp);
error2:
- free(data->buffer);
- DestroyRingBuffer(data->ring);
- snd_pcm_close(data->pcmHandle);
- free(data);
+ free(self->buffer);
+ self->buffer = NULL;
+ DestroyRingBuffer(self->ring);
+ self->ring = NULL;
+ snd_pcm_close(self->pcmHandle);
- Device->ExtraData = NULL;
return ALC_INVALID_VALUE;
}
-static void alsa_close_capture(ALCdevice *Device)
+static void ALCcaptureAlsa_close(ALCcaptureAlsa *self)
{
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ snd_pcm_close(self->pcmHandle);
+ DestroyRingBuffer(self->ring);
- snd_pcm_close(data->pcmHandle);
- DestroyRingBuffer(data->ring);
+ free(self->buffer);
+ self->buffer = NULL;
+}
- free(data->buffer);
- free(data);
- Device->ExtraData = NULL;
+static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
+{
+ int err = snd_pcm_start(self->pcmHandle);
+ if(err < 0)
+ {
+ ERR("start failed: %s\n", snd_strerror(err));
+ aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+ return ALC_FALSE;
+ }
+
+ self->doCapture = AL_TRUE;
+ return ALC_TRUE;
}
-static void alsa_start_capture(ALCdevice *Device)
+static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
{
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ ALCuint avail;
int err;
- err = snd_pcm_start(data->pcmHandle);
- if(err < 0)
+ /* OpenAL requires access to unread audio after stopping, but ALSA's
+ * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
+ * available now so it'll be available later after the drop. */
+ avail = ALCcaptureAlsa_availableSamples(self);
+ if(!self->ring && avail > 0)
{
- ERR("start failed: %s\n", snd_strerror(err));
- aluHandleDisconnect(Device);
+ /* The ring buffer implicitly captures when checking availability.
+ * Direct access needs to explicitly capture it into temp storage. */
+ ALsizei size;
+ void *ptr;
+
+ size = snd_pcm_frames_to_bytes(self->pcmHandle, avail);
+ ptr = realloc(self->buffer, size);
+ if(ptr)
+ {
+ self->buffer = ptr;
+ ALCcaptureAlsa_captureSamples(self, self->buffer, avail);
+ self->size = size;
+ }
}
- else
- data->doCapture = AL_TRUE;
+ err = snd_pcm_drop(self->pcmHandle);
+ if(err < 0)
+ ERR("drop failed: %s\n", snd_strerror(err));
+ self->doCapture = AL_FALSE;
}
-static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
+static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples)
{
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- if(data->ring)
+ if(self->ring)
{
- ReadRingBuffer(data->ring, Buffer, Samples);
+ ReadRingBuffer(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
- data->last_avail -= Samples;
- while(Device->Connected && Samples > 0)
+ self->last_avail -= samples;
+ while(device->Connected && samples > 0)
{
snd_pcm_sframes_t amt = 0;
- if(data->size > 0)
+ if(self->size > 0)
{
/* First get any data stored from the last stop */
- amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
- if((snd_pcm_uframes_t)amt > Samples) amt = Samples;
+ amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
+ if((snd_pcm_uframes_t)amt > samples) amt = samples;
- amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
- memmove(Buffer, data->buffer, amt);
+ amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt);
+ memmove(buffer, self->buffer, amt);
- if(data->size > amt)
+ if(self->size > amt)
{
- memmove(data->buffer, data->buffer+amt, data->size - amt);
- data->size -= amt;
+ memmove(self->buffer, self->buffer+amt, self->size - amt);
+ self->size -= amt;
}
else
{
- free(data->buffer);
- data->buffer = NULL;
- data->size = 0;
+ free(self->buffer);
+ self->buffer = NULL;
+ self->size = 0;
}
- amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
+ amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt);
}
- else if(data->doCapture)
- amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
+ else if(self->doCapture)
+ amt = snd_pcm_readi(self->pcmHandle, buffer, samples);
if(amt < 0)
{
ERR("read error: %s\n", snd_strerror(amt));
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
+ if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0)
{
- amt = snd_pcm_start(data->pcmHandle);
+ amt = snd_pcm_start(self->pcmHandle);
if(amt >= 0)
- amt = snd_pcm_avail_update(data->pcmHandle);
+ amt = snd_pcm_avail_update(self->pcmHandle);
}
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(Device);
+ aluHandleDisconnect(device);
break;
}
/* If the amount available is less than what's asked, we lost it
* during recovery. So just give silence instead. */
- if((snd_pcm_uframes_t)amt < Samples)
+ if((snd_pcm_uframes_t)amt < samples)
break;
continue;
}
- Buffer = (ALbyte*)Buffer + amt;
- Samples -= amt;
+ buffer = (ALbyte*)buffer + amt;
+ samples -= amt;
}
- if(Samples > 0)
- memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
- snd_pcm_frames_to_bytes(data->pcmHandle, Samples));
+ if(samples > 0)
+ memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0),
+ snd_pcm_frames_to_bytes(self->pcmHandle, samples));
return ALC_NO_ERROR;
}
-static ALCuint alsa_available_samples(ALCdevice *Device)
+static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
{
- alsa_data *data = (alsa_data*)Device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t avail = 0;
- if(Device->Connected && data->doCapture)
- avail = snd_pcm_avail_update(data->pcmHandle);
+ if(device->Connected && self->doCapture)
+ avail = snd_pcm_avail_update(self->pcmHandle);
if(avail < 0)
{
ERR("avail update failed: %s\n", snd_strerror(avail));
- if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
+ if((avail=snd_pcm_recover(self->pcmHandle, avail, 1)) >= 0)
{
- if(data->doCapture)
- avail = snd_pcm_start(data->pcmHandle);
+ if(self->doCapture)
+ avail = snd_pcm_start(self->pcmHandle);
if(avail >= 0)
- avail = snd_pcm_avail_update(data->pcmHandle);
+ avail = snd_pcm_avail_update(self->pcmHandle);
}
if(avail < 0)
{
ERR("restore error: %s\n", snd_strerror(avail));
- aluHandleDisconnect(Device);
+ aluHandleDisconnect(device);
}
}
- if(!data->ring)
+ if(!self->ring)
{
if(avail < 0) avail = 0;
- avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
- if(avail > data->last_avail) data->last_avail = avail;
- return data->last_avail;
+ avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
+ if(avail > self->last_avail) self->last_avail = avail;
+ return self->last_avail;
}
while(avail > 0)
{
snd_pcm_sframes_t amt;
- amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
+ amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
if(avail < amt) amt = avail;
- amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
+ amt = snd_pcm_readi(self->pcmHandle, self->buffer, amt);
if(amt < 0)
{
ERR("read error: %s\n", snd_strerror(amt));
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
+ if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0)
{
- if(data->doCapture)
- amt = snd_pcm_start(data->pcmHandle);
+ if(self->doCapture)
+ amt = snd_pcm_start(self->pcmHandle);
if(amt >= 0)
- amt = snd_pcm_avail_update(data->pcmHandle);
+ amt = snd_pcm_avail_update(self->pcmHandle);
}
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(Device);
+ aluHandleDisconnect(device);
break;
}
avail = amt;
continue;
}
- WriteRingBuffer(data->ring, data->buffer, amt);
+ WriteRingBuffer(self->ring, self->buffer, amt);
avail -= amt;
}
- return RingBufferSize(data->ring);
-}
-
-static void alsa_stop_capture(ALCdevice *Device)
-{
- alsa_data *data = (alsa_data*)Device->ExtraData;
- ALCuint avail;
- int err;
-
- /* OpenAL requires access to unread audio after stopping, but ALSA's
- * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
- * available now so it'll be available later after the drop. */
- avail = alsa_available_samples(Device);
- if(!data->ring && avail > 0)
- {
- /* The ring buffer implicitly captures when checking availability.
- * Direct access needs to explicitly capture it into temp storage. */
- ALsizei size;
- void *ptr;
-
- size = snd_pcm_frames_to_bytes(data->pcmHandle, avail);
- ptr = realloc(data->buffer, size);
- if(ptr)
- {
- data->buffer = ptr;
- alsa_capture_samples(Device, data->buffer, avail);
- data->size = size;
- }
- }
- err = snd_pcm_drop(data->pcmHandle);
- if(err < 0)
- ERR("drop failed: %s\n", snd_strerror(err));
- data->doCapture = AL_FALSE;
+ return RingBufferSize(self->ring);
}
-
-static ALint64 alsa_get_latency(ALCdevice *device)
+static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self)
{
- alsa_data *data = (alsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t delay = 0;
int err;
- if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0)
+ if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
{
ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
return 0;
@@ -1279,33 +1287,28 @@ static ALint64 alsa_get_latency(ALCdevice *device)
return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
}
+static void ALCcaptureAlsa_Delete(ALCcaptureAlsa *self)
+{
+ free(self);
+}
+
+DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
+
+
-static const BackendFuncs alsa_funcs = {
- alsa_open_playback,
- alsa_close_playback,
- alsa_reset_playback,
- alsa_start_playback,
- alsa_stop_playback,
- alsa_open_capture,
- alsa_close_capture,
- alsa_start_capture,
- alsa_stop_capture,
- alsa_capture_samples,
- alsa_available_samples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
- alsa_get_latency
-};
-
-ALCboolean alc_alsa_init(BackendFuncs *func_list)
+typedef struct ALCalsaBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCalsaBackendFactory;
+#define ALCALSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCalsaBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self))
{
if(!alsa_load())
return ALC_FALSE;
- *func_list = alsa_funcs;
return ALC_TRUE;
}
-void alc_alsa_deinit(void)
+static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self))
{
ALuint i;
@@ -1334,7 +1337,14 @@ void alc_alsa_deinit(void)
#endif
}
-void alc_alsa_probe(enum DevProbe type)
+static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
{
ALuint i;
@@ -1369,3 +1379,40 @@ void alc_alsa_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCplaybackAlsa *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCplaybackAlsa_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCcaptureAlsa *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCcaptureAlsa_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory);
+
+
+ALCbackendFactory *ALCalsaBackendFactory_getFactory(void)
+{
+ static ALCalsaBackendFactory factory = ALCALSABACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/backends/base.c b/Alc/backends/base.c
new file mode 100644
index 00000000..fe797562
--- /dev/null
+++ b/Alc/backends/base.c
@@ -0,0 +1,230 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+
+#include "backends/base.h"
+
+
+/* Base ALCbackend method implementations. */
+void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
+{
+ self->mDevice = device;
+ InitializeCriticalSection(&self->mMutex);
+}
+
+void ALCbackend_Destruct(ALCbackend *self)
+{
+ DeleteCriticalSection(&self->mMutex);
+}
+
+ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self))
+{
+ return ALC_FALSE;
+}
+
+ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples))
+{
+ return ALC_INVALID_DEVICE;
+}
+
+ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self))
+{
+ return 0;
+}
+
+ALint64 ALCbackend_getLatency(ALCbackend* UNUSED(self))
+{
+ return 0;
+}
+
+void ALCbackend_lock(ALCbackend *self)
+{
+ EnterCriticalSection(&self->mMutex);
+}
+
+void ALCbackend_unlock(ALCbackend *self)
+{
+ LeaveCriticalSection(&self->mMutex);
+}
+
+
+/* Base ALCbackendFactory method implementations. */
+void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
+{
+}
+
+
+/* Wrappers to use an old-style backend with the new interface. */
+typedef struct PlaybackWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+} PlaybackWrapper;
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
+static void PlaybackWrapper_close(PlaybackWrapper *self);
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
+static void PlaybackWrapper_stop(PlaybackWrapper *self);
+static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
+static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
+static void PlaybackWrapper_Delete(PlaybackWrapper *self);
+DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
+}
+
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->OpenPlayback(device, name);
+}
+
+static void PlaybackWrapper_close(PlaybackWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->Funcs->ClosePlayback(device);
+}
+
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->ResetPlayback(device);
+}
+
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->StartPlayback(device);
+}
+
+static void PlaybackWrapper_stop(PlaybackWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->Funcs->StopPlayback(device);
+}
+
+static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->GetLatency(device);
+}
+
+static void PlaybackWrapper_Delete(PlaybackWrapper *self)
+{
+ free(self);
+}
+
+
+typedef struct CaptureWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+} CaptureWrapper;
+
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
+static void CaptureWrapper_close(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
+static void CaptureWrapper_stop(CaptureWrapper *self);
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
+static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
+static void CaptureWrapper_Delete(CaptureWrapper *self);
+DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
+
+
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(CaptureWrapper, ALCbackend, self);
+}
+
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->OpenCapture(device, name);
+}
+
+static void CaptureWrapper_close(CaptureWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->Funcs->CloseCapture(device);
+}
+
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->Funcs->StartCapture(device);
+ return ALC_TRUE;
+}
+
+static void CaptureWrapper_stop(CaptureWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->Funcs->StopCapture(device);
+}
+
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->CaptureSamples(device, buffer, samples);
+}
+
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->AvailableSamples(device);
+}
+
+static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return device->Funcs->GetLatency(device);
+}
+
+static void CaptureWrapper_Delete(CaptureWrapper *self)
+{
+ free(self);
+}
+
+
+ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ PlaybackWrapper *backend;
+
+ backend = malloc(sizeof(*backend));
+ if(!backend) return NULL;
+
+ PlaybackWrapper_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ if(type == ALCbackend_Capture)
+ {
+ CaptureWrapper *backend;
+
+ backend = malloc(sizeof(*backend));
+ if(!backend) return NULL;
+
+ CaptureWrapper_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
diff --git a/Alc/backends/base.h b/Alc/backends/base.h
new file mode 100644
index 00000000..1bbc1fb0
--- /dev/null
+++ b/Alc/backends/base.h
@@ -0,0 +1,133 @@
+#ifndef AL_BACKENDS_BASE_H
+#define AL_BACKENDS_BASE_H
+
+#include "alMain.h"
+#include "compat.h"
+
+
+struct ALCbackendVtable;
+
+typedef struct ALCbackend {
+ const struct ALCbackendVtable *vtbl;
+
+ ALCdevice *mDevice;
+
+ CRITICAL_SECTION mMutex;
+} ALCbackend;
+
+void ALCbackend_Construct(ALCbackend *self, ALCdevice *device);
+void ALCbackend_Destruct(ALCbackend *self);
+ALCboolean ALCbackend_reset(ALCbackend *self);
+ALCenum ALCbackend_captureSamples(ALCbackend *self, void *buffer, ALCuint samples);
+ALCuint ALCbackend_availableSamples(ALCbackend *self);
+ALint64 ALCbackend_getLatency(ALCbackend *self);
+void ALCbackend_lock(ALCbackend *self);
+void ALCbackend_unlock(ALCbackend *self);
+
+struct ALCbackendVtable {
+ void (*const Destruct)(ALCbackend*);
+
+ ALCenum (*const open)(ALCbackend*, const ALCchar*);
+ void (*const close)(ALCbackend*);
+
+ ALCboolean (*const reset)(ALCbackend*);
+ ALCboolean (*const start)(ALCbackend*);
+ void (*const stop)(ALCbackend*);
+
+ ALCenum (*const captureSamples)(ALCbackend*, void*, ALCuint);
+ ALCuint (*const availableSamples)(ALCbackend*);
+
+ ALint64 (*const getLatency)(ALCbackend*);
+
+ void (*const lock)(ALCbackend*);
+ void (*const unlock)(ALCbackend*);
+
+ void (*const Delete)(ALCbackend*);
+};
+
+#define DECLARE_ALCBACKEND_VTABLE(T) \
+static const struct ALCbackendVtable T##_ALCbackend_vtable
+
+#define DEFINE_ALCBACKEND_VTABLE(T) \
+DECLARE_THUNK(T, ALCbackend, void, Destruct) \
+DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \
+DECLARE_THUNK(T, ALCbackend, void, close) \
+DECLARE_THUNK(T, ALCbackend, ALCboolean, reset) \
+DECLARE_THUNK(T, ALCbackend, ALCboolean, start) \
+DECLARE_THUNK(T, ALCbackend, void, stop) \
+DECLARE_THUNK2(T, ALCbackend, ALCenum, captureSamples, void*, ALCuint) \
+DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \
+DECLARE_THUNK(T, ALCbackend, ALint64, getLatency) \
+DECLARE_THUNK(T, ALCbackend, void, lock) \
+DECLARE_THUNK(T, ALCbackend, void, unlock) \
+DECLARE_THUNK(T, ALCbackend, void, Delete) \
+ \
+DECLARE_ALCBACKEND_VTABLE(T) = { \
+ T##_ALCbackend_Destruct, \
+ \
+ T##_ALCbackend_open, \
+ T##_ALCbackend_close, \
+ T##_ALCbackend_reset, \
+ T##_ALCbackend_start, \
+ T##_ALCbackend_stop, \
+ T##_ALCbackend_captureSamples, \
+ T##_ALCbackend_availableSamples, \
+ T##_ALCbackend_getLatency, \
+ T##_ALCbackend_lock, \
+ T##_ALCbackend_unlock, \
+ \
+ T##_ALCbackend_Delete, \
+}
+
+
+typedef enum ALCbackend_Type {
+ ALCbackend_Playback,
+ ALCbackend_Capture,
+ ALCbackend_Loopback
+} ALCbackend_Type;
+
+
+struct ALCbackendFactoryVtable;
+
+typedef struct ALCbackendFactory {
+ const struct ALCbackendFactoryVtable *vtbl;
+} ALCbackendFactory;
+
+void ALCbackendFactory_deinit(ALCbackendFactory *self);
+
+struct ALCbackendFactoryVtable {
+ ALCboolean (*const init)(ALCbackendFactory *self);
+ void (*const deinit)(ALCbackendFactory *self);
+
+ ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type);
+
+ void (*const probe)(ALCbackendFactory *self, enum DevProbe type);
+
+ ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+};
+
+#define DEFINE_ALCBACKENDFACTORY_VTABLE(T) \
+DECLARE_THUNK(T, ALCbackendFactory, ALCboolean, init) \
+DECLARE_THUNK(T, ALCbackendFactory, void, deinit) \
+DECLARE_THUNK1(T, ALCbackendFactory, ALCboolean, querySupport, ALCbackend_Type) \
+DECLARE_THUNK1(T, ALCbackendFactory, void, probe, enum DevProbe) \
+DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \
+ \
+static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
+ T##_ALCbackendFactory_init, \
+ T##_ALCbackendFactory_deinit, \
+ T##_ALCbackendFactory_querySupport, \
+ T##_ALCbackendFactory_probe, \
+ T##_ALCbackendFactory_createBackend, \
+}
+
+
+ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
+ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
+ALCbackendFactory *ALCossBackendFactory_getFactory(void);
+ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
+ALCbackendFactory *ALCloopbackFactory_getFactory(void);
+
+ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type);
+
+#endif /* AL_BACKENDS_BASE_H */
diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c
index 150f37ac..5c9b69c8 100644
--- a/Alc/backends/coreaudio.c
+++ b/Alc/backends/coreaudio.c
@@ -677,8 +677,6 @@ static const BackendFuncs ca_funcs = {
ca_stop_capture,
ca_capture_samples,
ca_available_samples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c
index c6f666e1..6b108fba 100644
--- a/Alc/backends/dsound.c
+++ b/Alc/backends/dsound.c
@@ -34,13 +34,22 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
#ifndef DSSPEAKER_5POINT1
-#define DSSPEAKER_5POINT1 6
+# define DSSPEAKER_5POINT1 0x00000006
#endif
#ifndef DSSPEAKER_7POINT1
-#define DSSPEAKER_7POINT1 7
+# define DSSPEAKER_7POINT1 0x00000007
#endif
+#ifndef DSSPEAKER_7POINT1_SURROUND
+# define DSSPEAKER_7POINT1_SURROUND 0x00000008
+#endif
+#ifndef DSSPEAKER_5POINT1_SURROUND
+# define DSSPEAKER_5POINT1_SURROUND 0x00000009
+#endif
+
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
@@ -67,7 +76,7 @@ typedef struct {
HANDLE NotifyEvent;
volatile int killNow;
- ALvoid *thread;
+ althread_t thread;
} DSoundPlaybackData;
typedef struct {
@@ -121,7 +130,7 @@ static ALCboolean DSoundLoad(void)
}
-static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
+static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
{
LPOLESTR guidstr = NULL;
char str[1024];
@@ -130,9 +139,6 @@ static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR
int count;
ALuint i;
- (void)data;
- (void)drvname;
-
if(!guid)
return TRUE;
@@ -171,7 +177,7 @@ static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR
}
-static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
+static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR UNUSED(drvname), LPVOID UNUSED(data))
{
LPOLESTR guidstr = NULL;
char str[1024];
@@ -180,9 +186,6 @@ static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR d
int count;
ALuint i;
- (void)data;
- (void)drvname;
-
if(!guid)
return TRUE;
@@ -221,7 +224,7 @@ static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR d
}
-static ALuint DSoundPlaybackProc(ALvoid *ptr)
+FORCE_ALIGN static ALuint DSoundPlaybackProc(ALvoid *ptr)
{
ALCdevice *Device = (ALCdevice*)ptr;
DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
@@ -237,6 +240,7 @@ static ALuint DSoundPlaybackProc(ALvoid *ptr)
HRESULT err;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
memset(&DSBCaps, 0, sizeof(DSBCaps));
DSBCaps.dwSize = sizeof(DSBCaps);
@@ -466,9 +470,9 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
device->FmtChans = DevFmtStereo;
else if(speakers == DSSPEAKER_QUAD)
device->FmtChans = DevFmtQuad;
- else if(speakers == DSSPEAKER_5POINT1)
+ else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND)
device->FmtChans = DevFmtX51;
- else if(speakers == DSSPEAKER_7POINT1)
+ else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
device->FmtChans = DevFmtX71;
else
ERR("Unknown system speaker config: 0x%lx\n", speakers);
@@ -630,8 +634,7 @@ static ALCboolean DSoundStartPlayback(ALCdevice *device)
{
DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData;
- data->thread = StartThread(DSoundPlaybackProc, device);
- if(data->thread == NULL)
+ if(!StartThread(&data->thread, DSoundPlaybackProc, device))
return ALC_FALSE;
return ALC_TRUE;
@@ -952,8 +955,6 @@ static const BackendFuncs DSoundFuncs = {
DSoundStopCapture,
DSoundCaptureSamples,
DSoundAvailableSamples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c
index e1bdd3c1..cd5b1a1e 100644
--- a/Alc/backends/loopback.c
+++ b/Alc/backends/loopback.c
@@ -25,64 +25,116 @@
#include "alMain.h"
#include "alu.h"
+#include "backends/base.h"
-static ALCenum loopback_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+typedef struct ALCloopback {
+ DERIVE_FROM_TYPE(ALCbackend);
+} ALCloopback;
+
+static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCloopback, ALCbackend, void, Destruct)
+static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name);
+static void ALCloopback_close(ALCloopback *self);
+static ALCboolean ALCloopback_reset(ALCloopback *self);
+static ALCboolean ALCloopback_start(ALCloopback *self);
+static void ALCloopback_stop(ALCloopback *self);
+static DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCloopback, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock)
+static void ALCloopback_Delete(ALCloopback *self);
+DEFINE_ALCBACKEND_VTABLE(ALCloopback);
+
+
+static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device)
{
- device->DeviceName = strdup(deviceName);
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCloopback, ALCbackend, self);
+}
+
+
+static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+
+ device->DeviceName = strdup(name);
return ALC_NO_ERROR;
}
-static void loopback_close_playback(ALCdevice *device)
+static void ALCloopback_close(ALCloopback* UNUSED(self))
{
- (void)device;
}
-static ALCboolean loopback_reset_playback(ALCdevice *device)
+static ALCboolean ALCloopback_reset(ALCloopback *self)
{
- SetDefaultWFXChannelOrder(device);
+ SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
return ALC_TRUE;
}
-static ALCboolean loopback_start_playback(ALCdevice *device)
+static ALCboolean ALCloopback_start(ALCloopback* UNUSED(self))
{
return ALC_TRUE;
- (void)device;
}
-static void loopback_stop_playback(ALCdevice *device)
+static void ALCloopback_stop(ALCloopback* UNUSED(self))
+{
+}
+
+
+static void ALCloopback_Delete(ALCloopback *self)
{
- (void)device;
+ free(self);
}
-static const BackendFuncs loopback_funcs = {
- loopback_open_playback,
- loopback_close_playback,
- loopback_reset_playback,
- loopback_start_playback,
- loopback_stop_playback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_loopback_init(BackendFuncs *func_list)
+typedef struct ALCloopbackFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCloopbackFactory;
+#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCloopbackFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCloopbackFactory_getFactory(void);
+static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self);
+static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type);
+static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type);
+static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory);
+
+
+ALCbackendFactory *ALCloopbackFactory_getFactory(void)
+{
+ static ALCloopbackFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
+
+static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory* UNUSED(self))
{
- *func_list = loopback_funcs;
return ALC_TRUE;
}
-void alc_loopback_deinit(void)
+static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(self), ALCbackend_Type type)
{
+ if(type == ALCbackend_Loopback)
+ return ALC_TRUE;
+ return ALC_FALSE;
}
-void alc_loopback_probe(enum DevProbe type)
+static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type))
{
- (void)type;
+}
+
+static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ ALCloopback *backend;
+
+ assert(type == ALCbackend_Loopback);
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCloopback_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index 2555c7f3..fa7c54f9 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -40,6 +40,8 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
@@ -69,7 +71,7 @@ typedef struct {
volatile UINT32 Padding;
volatile int killNow;
- ALvoid *thread;
+ althread_t thread;
} MMDevApiData;
@@ -218,7 +220,7 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu
}
-static ALuint MMDevApiProc(ALvoid *ptr)
+FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
{
ALCdevice *device = ptr;
MMDevApiData *data = device->ExtraData;
@@ -238,6 +240,7 @@ static ALuint MMDevApiProc(ALvoid *ptr)
}
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
update_size = device->UpdateSize;
buffer_len = update_size * device->NumUpdates;
@@ -676,8 +679,7 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
if(SUCCEEDED(hr))
{
data->render = ptr;
- data->thread = StartThread(MMDevApiProc, device);
- if(!data->thread)
+ if(!StartThread(&data->thread, MMDevApiProc, device))
{
if(data->render)
IAudioRenderClient_Release(data->render);
@@ -878,6 +880,9 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
CloseHandle(data->MsgEvent);
data->MsgEvent = NULL;
+ free(data->devid);
+ data->devid = NULL;
+
free(data);
device->ExtraData = NULL;
@@ -963,8 +968,6 @@ static const BackendFuncs MMDevApiFuncs = {
NULL,
NULL,
NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
MMDevApiGetLatency
};
diff --git a/Alc/backends/null.c b/Alc/backends/null.c
index 93b38063..a7056369 100644
--- a/Alc/backends/null.c
+++ b/Alc/backends/null.c
@@ -27,139 +27,175 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+#include "backends/base.h"
-typedef struct {
- volatile int killNow;
- ALvoid *thread;
-} null_data;
+typedef struct ALCnullBackend {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ volatile int killNow;
+ althread_t thread;
+} ALCnullBackend;
+DECLARE_ALCBACKEND_VTABLE(ALCnullBackend);
+
+static ALuint ALCnullBackend_mixerProc(ALvoid *ptr);
+
+static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
+static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name);
+static void ALCnullBackend_close(ALCnullBackend *self);
+static ALCboolean ALCnullBackend_reset(ALCnullBackend *self);
+static ALCboolean ALCnullBackend_start(ALCnullBackend *self);
+static void ALCnullBackend_stop(ALCnullBackend *self);
+static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock)
static const ALCchar nullDevice[] = "No Output";
-static ALuint NullProc(ALvoid *ptr)
+
+static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- null_data *data = (null_data*)Device->ExtraData;
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCnullBackend, ALCbackend, self);
+}
+
+
+static ALuint ALCnullBackend_mixerProc(ALvoid *ptr)
+{
+ ALCnullBackend *self = (ALCnullBackend*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint now, start;
ALuint64 avail, done;
- const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
- Device->Frequency / 2;
+
+ SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
done = 0;
start = timeGetTime();
- while(!data->killNow && Device->Connected)
+ while(!self->killNow && device->Connected)
{
now = timeGetTime();
- avail = (ALuint64)(now-start) * Device->Frequency / 1000;
+ avail = (ALuint64)(now-start) * device->Frequency / 1000;
if(avail < done)
{
/* Timer wrapped (50 days???). Add the remainder of the cycle to
* the available count and reset the number of samples done */
- avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done;
+ avail += (U64(1)<<32)*device->Frequency/1000 - done;
done = 0;
}
- if(avail-done < Device->UpdateSize)
+ if(avail-done < device->UpdateSize)
{
+ ALuint restTime = (ALuint)((device->UpdateSize - (avail-done)) * 1000 /
+ device->Frequency);
Sleep(restTime);
continue;
}
- while(avail-done >= Device->UpdateSize)
- {
- aluMixData(Device, NULL, Device->UpdateSize);
- done += Device->UpdateSize;
- }
+ do {
+ aluMixData(device, NULL, device->UpdateSize);
+ done += device->UpdateSize;
+ } while(avail-done >= device->UpdateSize);
}
return 0;
}
-static ALCenum null_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
{
- null_data *data;
+ ALCdevice *device;
- if(!deviceName)
- deviceName = nullDevice;
- else if(strcmp(deviceName, nullDevice) != 0)
+ if(!name)
+ name = nullDevice;
+ else if(strcmp(name, nullDevice) != 0)
return ALC_INVALID_VALUE;
- data = (null_data*)calloc(1, sizeof(*data));
+ device = STATIC_CAST(ALCbackend, self)->mDevice;
+ device->DeviceName = strdup(name);
- device->DeviceName = strdup(deviceName);
- device->ExtraData = data;
return ALC_NO_ERROR;
}
-static void null_close_playback(ALCdevice *device)
+static void ALCnullBackend_close(ALCnullBackend* UNUSED(self))
{
- null_data *data = (null_data*)device->ExtraData;
+}
- free(data);
- device->ExtraData = NULL;
+static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
+{
+ SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
+ return ALC_TRUE;
}
-static ALCboolean null_reset_playback(ALCdevice *device)
+static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
{
- SetDefaultWFXChannelOrder(device);
+ if(!StartThread(&self->thread, ALCnullBackend_mixerProc, self))
+ return ALC_FALSE;
return ALC_TRUE;
}
-static ALCboolean null_start_playback(ALCdevice *device)
+static void ALCnullBackend_stop(ALCnullBackend *self)
{
- null_data *data = (null_data*)device->ExtraData;
+ if(!self->thread)
+ return;
- data->thread = StartThread(NullProc, device);
- if(data->thread == NULL)
- return ALC_FALSE;
+ self->killNow = 1;
+ StopThread(self->thread);
+ self->thread = NULL;
- return ALC_TRUE;
+ self->killNow = 0;
}
-static void null_stop_playback(ALCdevice *device)
+
+static void ALCnullBackend_Delete(ALCnullBackend *self)
{
- null_data *data = (null_data*)device->ExtraData;
+ free(self);
+}
- if(!data->thread)
- return;
+DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
+
+
+typedef struct ALCnullBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCnullBackendFactory;
+#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
+
+static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self);
+static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type);
+static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory);
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
- data->killNow = 0;
+ALCbackendFactory *ALCnullBackendFactory_getFactory(void)
+{
+ static ALCnullBackendFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}
-static const BackendFuncs null_funcs = {
- null_open_playback,
- null_close_playback,
- null_reset_playback,
- null_start_playback,
- null_stop_playback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_null_init(BackendFuncs *func_list)
+static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self))
{
- *func_list = null_funcs;
return ALC_TRUE;
}
-void alc_null_deinit(void)
+static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type)
{
+ if(type == ALCbackend_Playback)
+ return ALC_TRUE;
+ return ALC_FALSE;
}
-void alc_null_probe(enum DevProbe type)
+static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -170,3 +206,17 @@ void alc_null_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ ALCnullBackend *backend;
+
+ assert(type == ALCbackend_Playback);
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCnullBackend_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+}
diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c
index 1a104029..76cbaf1a 100644
--- a/Alc/backends/opensl.c
+++ b/Alc/backends/opensl.c
@@ -83,6 +83,10 @@ typedef struct SLDataLocator_AndroidSimpleBufferQueue {
#define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b)))
+/* Should start using these generic callers instead of the name-specific ones above. */
+#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
+#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
+
typedef struct {
/* engine interfaces */
@@ -97,6 +101,7 @@ typedef struct {
void *buffer;
ALuint bufferSize;
+ ALuint curBuffer;
ALuint frameSize;
} osl_data;
@@ -175,12 +180,16 @@ static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
ALCdevice *Device = context;
osl_data *data = Device->ExtraData;
+ ALvoid *buf;
SLresult result;
- aluMixData(Device, data->buffer, data->bufferSize/data->frameSize);
+ buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
+ aluMixData(Device, buf, data->bufferSize/data->frameSize);
- result = (*bq)->Enqueue(bq, data->buffer, data->bufferSize);
+ result = (*bq)->Enqueue(bq, buf, data->bufferSize);
PRINTERR(result, "bq->Enqueue");
+
+ data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
}
@@ -354,7 +363,7 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
{
data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
data->bufferSize = Device->UpdateSize * data->frameSize;
- data->buffer = calloc(1, data->bufferSize);
+ data->buffer = calloc(Device->NumUpdates, data->bufferSize);
if(!data->buffer)
{
result = SL_RESULT_MEMORY_FAILURE;
@@ -366,10 +375,12 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
{
if(SL_RESULT_SUCCESS == result)
{
- result = (*bufferQueue)->Enqueue(bufferQueue, data->buffer, data->bufferSize);
+ ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize;
+ result = (*bufferQueue)->Enqueue(bufferQueue, buf, data->bufferSize);
PRINTERR(result, "bufferQueue->Enqueue");
}
}
+ data->curBuffer = 0;
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player);
@@ -401,6 +412,25 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
static void opensl_stop_playback(ALCdevice *Device)
{
osl_data *data = Device->ExtraData;
+ SLPlayItf player;
+ SLAndroidSimpleBufferQueueItf bufferQueue;
+ SLresult result;
+
+ result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
+ PRINTERR(result, "bufferQueue->GetInterface");
+ if(SL_RESULT_SUCCESS == result)
+ {
+ result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
+ PRINTERR(result, "player->SetPlayState");
+ }
+
+ result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
+ PRINTERR(result, "bufferQueue->GetInterface");
+ if(SL_RESULT_SUCCESS == result)
+ {
+ result = VCALL0(bufferQueue,Clear)();
+ PRINTERR(result, "bufferQueue->Clear");
+ }
free(data->buffer);
data->buffer = NULL;
@@ -420,8 +450,6 @@ static const BackendFuncs opensl_funcs = {
NULL,
NULL,
NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c
index 0ed49517..c79793c2 100644
--- a/Alc/backends/oss.c
+++ b/Alc/backends/oss.c
@@ -33,6 +33,10 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
#include <sys/soundcard.h>
@@ -47,24 +51,12 @@
#define SOUND_MIXER_WRITE MIXER_WRITE
#endif
+
static const ALCchar oss_device[] = "OSS Default";
static const char *oss_driver = "/dev/dsp";
static const char *oss_capture = "/dev/dsp";
-typedef struct {
- int fd;
- volatile int killNow;
- ALvoid *thread;
-
- ALubyte *mix_data;
- int data_size;
-
- RingBuffer *ring;
- int doCapture;
-} oss_data;
-
-
static int log2i(ALCuint x)
{
int y = 0;
@@ -77,34 +69,65 @@ static int log2i(ALCuint x)
}
-static ALuint OSSProc(ALvoid *ptr)
+typedef struct ALCplaybackOSS {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ int fd;
+
+ ALubyte *mix_data;
+ int data_size;
+
+ volatile int killNow;
+ althread_t thread;
+} ALCplaybackOSS;
+
+static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr);
+
+static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
+static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
+static void ALCplaybackOSS_close(ALCplaybackOSS *self);
+static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
+static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
+static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
+static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock)
+static void ALCplaybackOSS_Delete(ALCplaybackOSS *self);
+DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS);
+
+
+static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- oss_data *data = (oss_data*)Device->ExtraData;
+ ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALint frameSize;
ssize_t wrote;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
- frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
+ frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- while(!data->killNow && Device->Connected)
+ while(!self->killNow && device->Connected)
{
- ALint len = data->data_size;
- ALubyte *WritePtr = data->mix_data;
+ ALint len = self->data_size;
+ ALubyte *WritePtr = self->mix_data;
- aluMixData(Device, WritePtr, len/frameSize);
- while(len > 0 && !data->killNow)
+ aluMixData(device, WritePtr, len/frameSize);
+ while(len > 0 && !self->killNow)
{
- wrote = write(data->fd, WritePtr, len);
+ wrote = write(self->fd, WritePtr, len);
if(wrote < 0)
{
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
{
ERR("write failed: %s\n", strerror(errno));
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCplaybackOSS_lock(self);
+ aluHandleDisconnect(device);
+ ALCplaybackOSS_unlock(self);
break;
}
@@ -120,77 +143,45 @@ static ALuint OSSProc(ALvoid *ptr)
return 0;
}
-static ALuint OSSCaptureProc(ALvoid *ptr)
-{
- ALCdevice *Device = (ALCdevice*)ptr;
- oss_data *data = (oss_data*)Device->ExtraData;
- int frameSize;
- int amt;
-
- SetRTPriority();
-
- frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
-
- while(!data->killNow)
- {
- amt = read(data->fd, data->mix_data, data->data_size);
- if(amt < 0)
- {
- ERR("read failed: %s\n", strerror(errno));
- ALCdevice_Lock(Device);
- aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
- break;
- }
- if(amt == 0)
- {
- Sleep(1);
- continue;
- }
- if(data->doCapture)
- WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
- }
- return 0;
+static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCplaybackOSS, ALCbackend, self);
}
-static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
{
- oss_data *data;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- if(!deviceName)
- deviceName = oss_device;
- else if(strcmp(deviceName, oss_device) != 0)
+ if(!name)
+ name = oss_device;
+ else if(strcmp(name, oss_device) != 0)
return ALC_INVALID_VALUE;
- data = (oss_data*)calloc(1, sizeof(oss_data));
- data->killNow = 0;
+ self->killNow = 0;
- data->fd = open(oss_driver, O_WRONLY);
- if(data->fd == -1)
+ self->fd = open(oss_driver, O_WRONLY);
+ if(self->fd == -1)
{
- free(data);
ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
- device->DeviceName = strdup(deviceName);
- device->ExtraData = data;
+ device->DeviceName = strdup(name);
+
return ALC_NO_ERROR;
}
-static void oss_close_playback(ALCdevice *device)
+static void ALCplaybackOSS_close(ALCplaybackOSS *self)
{
- oss_data *data = (oss_data*)device->ExtraData;
-
- close(data->fd);
- free(data);
- device->ExtraData = NULL;
+ close(self->fd);
+ self->fd = -1;
}
-static ALCboolean oss_reset_playback(ALCdevice *device)
+static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
{
- oss_data *data = (oss_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
@@ -241,11 +232,11 @@ static ALCboolean oss_reset_playback(ALCdevice *device)
}
/* Don't fail if SETFRAGMENT fails. We can handle just about anything
* that's reported back via GETOSPACE */
- ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
+ ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info));
if(0)
{
err:
@@ -277,69 +268,142 @@ static ALCboolean oss_reset_playback(ALCdevice *device)
return ALC_TRUE;
}
-static ALCboolean oss_start_playback(ALCdevice *device)
+static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
{
- oss_data *data = (oss_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->mix_data = calloc(1, data->data_size);
+ self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ self->mix_data = calloc(1, self->data_size);
- data->thread = StartThread(OSSProc, device);
- if(data->thread == NULL)
+ if(!StartThread(&self->thread, ALCplaybackOSS_mixerProc, self))
{
- free(data->mix_data);
- data->mix_data = NULL;
+ free(self->mix_data);
+ self->mix_data = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
-static void oss_stop_playback(ALCdevice *device)
+static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
{
- oss_data *data = (oss_data*)device->ExtraData;
-
- if(!data->thread)
+ if(!self->thread)
return;
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
+ self->killNow = 1;
+ StopThread(self->thread);
+ self->thread = NULL;
- data->killNow = 0;
- if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
+ self->killNow = 0;
+ if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
ERR("Error resetting device: %s\n", strerror(errno));
- free(data->mix_data);
- data->mix_data = NULL;
+ free(self->mix_data);
+ self->mix_data = NULL;
+}
+
+static void ALCplaybackOSS_Delete(ALCplaybackOSS *self)
+{
+ free(self);
}
-static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
+typedef struct ALCcaptureOSS {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ int fd;
+
+ ALubyte *read_data;
+ int data_size;
+
+ RingBuffer *ring;
+ int doCapture;
+
+ volatile int killNow;
+ althread_t thread;
+} ALCcaptureOSS;
+
+static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr);
+
+static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
+static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
+static void ALCcaptureOSS_close(ALCcaptureOSS *self);
+static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
+static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
+static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
+static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
+static void ALCcaptureOSS_Delete(ALCcaptureOSS *self);
+DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
+
+
+static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
{
+ ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ int frameSize;
+ int amt;
+
+ SetRTPriority();
+ SetThreadName("alsoft-record");
+
+ frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+ while(!self->killNow)
+ {
+ amt = read(self->fd, self->read_data, self->data_size);
+ if(amt < 0)
+ {
+ ERR("read failed: %s\n", strerror(errno));
+ ALCcaptureOSS_lock(self);
+ aluHandleDisconnect(device);
+ ALCcaptureOSS_unlock(self);
+ break;
+ }
+ if(amt == 0)
+ {
+ Sleep(1);
+ continue;
+ }
+ if(self->doCapture)
+ WriteRingBuffer(self->ring, self->read_data, amt/frameSize);
+ }
+
+ return 0;
+}
+
+
+static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
+}
+
+static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
- oss_data *data;
int ossFormat;
int ossSpeed;
char *err;
- if(!deviceName)
- deviceName = oss_device;
- else if(strcmp(deviceName, oss_device) != 0)
+ if(!name)
+ name = oss_device;
+ else if(strcmp(name, oss_device) != 0)
return ALC_INVALID_VALUE;
- data = (oss_data*)calloc(1, sizeof(oss_data));
- data->killNow = 0;
-
- data->fd = open(oss_capture, O_RDONLY);
- if(data->fd == -1)
+ self->fd = open(oss_capture, O_RDONLY);
+ if(self->fd == -1)
{
- free(data);
ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
return ALC_INVALID_VALUE;
}
@@ -359,7 +423,6 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
- free(data);
ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
return ALC_INVALID_VALUE;
}
@@ -380,17 +443,17 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
err = #func; \
goto err; \
}
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
- CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+ CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info));
if(0)
{
err:
ERR("%s failed: %s\n", err, strerror(errno));
- close(data->fd);
- free(data);
+ close(self->fd);
+ self->fd = -1;
return ALC_INVALID_VALUE;
}
#undef CHECKERR
@@ -398,8 +461,8 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
{
ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
- close(data->fd);
- free(data);
+ close(self->fd);
+ self->fd = -1;
return ALC_INVALID_VALUE;
}
@@ -408,109 +471,119 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
(ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
{
ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
- close(data->fd);
- free(data);
+ close(self->fd);
+ self->fd = -1;
return ALC_INVALID_VALUE;
}
- data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
- if(!data->ring)
+ self->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
+ if(!self->ring)
{
ERR("Ring buffer create failed\n");
- close(data->fd);
- free(data);
+ close(self->fd);
+ self->fd = -1;
return ALC_OUT_OF_MEMORY;
}
- data->data_size = info.fragsize;
- data->mix_data = calloc(1, data->data_size);
+ self->data_size = info.fragsize;
+ self->read_data = calloc(1, self->data_size);
- device->ExtraData = data;
- data->thread = StartThread(OSSCaptureProc, device);
- if(data->thread == NULL)
+ if(!StartThread(&self->thread, ALCcaptureOSS_recordProc, self))
{
device->ExtraData = NULL;
- free(data->mix_data);
- free(data);
+ close(self->fd);
+ self->fd = -1;
return ALC_OUT_OF_MEMORY;
}
- device->DeviceName = strdup(deviceName);
+ device->DeviceName = strdup(name);
+
return ALC_NO_ERROR;
}
-static void oss_close_capture(ALCdevice *device)
+static void ALCcaptureOSS_close(ALCcaptureOSS *self)
{
- oss_data *data = (oss_data*)device->ExtraData;
- data->killNow = 1;
- StopThread(data->thread);
+ self->killNow = 1;
+ StopThread(self->thread);
+ self->killNow = 0;
- close(data->fd);
+ close(self->fd);
+ self->fd = -1;
- DestroyRingBuffer(data->ring);
+ DestroyRingBuffer(self->ring);
+ self->ring = NULL;
- free(data->mix_data);
- free(data);
- device->ExtraData = NULL;
+ free(self->read_data);
+ self->read_data = NULL;
}
-static void oss_start_capture(ALCdevice *Device)
+static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
{
- oss_data *data = (oss_data*)Device->ExtraData;
- data->doCapture = 1;
+ self->doCapture = 1;
+ return ALC_TRUE;
}
-static void oss_stop_capture(ALCdevice *Device)
+static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
{
- oss_data *data = (oss_data*)Device->ExtraData;
- data->doCapture = 0;
+ self->doCapture = 0;
}
-static ALCenum oss_capture_samples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
+static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
{
- oss_data *data = (oss_data*)Device->ExtraData;
- ReadRingBuffer(data->ring, pBuffer, lSamples);
+ ReadRingBuffer(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
-static ALCuint oss_available_samples(ALCdevice *Device)
+static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
+{
+ return RingBufferSize(self->ring);
+}
+
+void ALCcaptureOSS_Delete(ALCcaptureOSS *self)
+{
+ free(self);
+}
+
+
+
+typedef struct ALCossBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCossBackendFactory;
+#define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCossBackendFactory_getFactory(void);
+
+static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self);
+static DECLARE_FORWARD(ALCossBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type);
+static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory);
+
+
+ALCbackendFactory *ALCossBackendFactory_getFactory(void)
{
- oss_data *data = (oss_data*)Device->ExtraData;
- return RingBufferSize(data->ring);
+ static ALCossBackendFactory factory = ALCOSSBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}
-static const BackendFuncs oss_funcs = {
- oss_open_playback,
- oss_close_playback,
- oss_reset_playback,
- oss_start_playback,
- oss_stop_playback,
- oss_open_capture,
- oss_close_capture,
- oss_start_capture,
- oss_stop_capture,
- oss_capture_samples,
- oss_available_samples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_oss_init(BackendFuncs *func_list)
+ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
{
ConfigValueStr("oss", "device", &oss_driver);
ConfigValueStr("oss", "capture", &oss_capture);
- *func_list = oss_funcs;
return ALC_TRUE;
}
-void alc_oss_deinit(void)
+ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type)
{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
}
-void alc_oss_probe(enum DevProbe type)
+void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -535,3 +608,31 @@ void alc_oss_probe(enum DevProbe type)
break;
}
}
+
+ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCplaybackOSS *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCplaybackOSS_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCcaptureOSS *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCcaptureOSS_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c
index 2f576639..162788fc 100644
--- a/Alc/backends/portaudio.c
+++ b/Alc/backends/portaudio.c
@@ -26,6 +26,7 @@
#include "alMain.h"
#include "alu.h"
+#include "compat.h"
#include <portaudio.h>
@@ -35,7 +36,7 @@ static const ALCchar pa_device[] = "PortAudio Default";
#ifdef HAVE_DYNLOAD
static void *pa_handle;
-#define MAKE_FUNC(x) static typeof(x) * p##x
+#define MAKE_FUNC(x) static __typeof(x) * p##x
MAKE_FUNC(Pa_Initialize);
MAKE_FUNC(Pa_Terminate);
MAKE_FUNC(Pa_GetErrorText);
@@ -127,31 +128,23 @@ typedef struct {
} pa_data;
-static int pa_callback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData)
+static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+ const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCdevice *device = (ALCdevice*)userData;
- (void)inputBuffer;
- (void)timeInfo;
- (void)statusFlags;
-
aluMixData(device, outputBuffer, framesPerBuffer);
return 0;
}
-static int pa_capture_cb(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData)
+static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer),
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+ const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCdevice *device = (ALCdevice*)userData;
pa_data *data = (pa_data*)device->ExtraData;
- (void)outputBuffer;
- (void)timeInfo;
- (void)statusFlags;
-
WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
return 0;
}
@@ -381,6 +374,9 @@ static void pa_close_capture(ALCdevice *device)
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
+ DestroyRingBuffer(data->ring);
+ data->ring = NULL;
+
free(data);
device->ExtraData = NULL;
}
@@ -431,8 +427,6 @@ static const BackendFuncs pa_funcs = {
pa_stop_capture,
pa_capture_samples,
pa_available_samples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c
index af44e3de..e2ae52ae 100644
--- a/Alc/backends/pulseaudio.c
+++ b/Alc/backends/pulseaudio.c
@@ -25,6 +25,10 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
#include <pulse/pulseaudio.h>
@@ -39,7 +43,7 @@
#ifdef HAVE_DYNLOAD
static void *pa_handle;
-#define MAKE_FUNC(x) static typeof(x) * p##x
+#define MAKE_FUNC(x) static __typeof(x) * p##x
MAKE_FUNC(pa_context_unref);
MAKE_FUNC(pa_sample_spec_valid);
MAKE_FUNC(pa_frame_size);
@@ -187,45 +191,6 @@ MAKE_FUNC(pa_stream_begin_write);
#endif
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-typedef struct {
- char *device_name;
-
- const void *cap_store;
- size_t cap_len;
- size_t cap_remain;
-
- ALCuint last_readable;
-
- pa_buffer_attr attr;
- pa_sample_spec spec;
-
- pa_threaded_mainloop *loop;
-
- ALvoid *thread;
- volatile ALboolean killNow;
-
- pa_stream *stream;
- pa_context *context;
-} pulse_data;
-
-typedef struct {
- char *name;
- char *device_name;
-} DevMap;
-
-
-static DevMap *allDevNameMap;
-static ALuint numDevNames;
-static DevMap *allCaptureDevNameMap;
-static ALuint numCaptureDevNames;
-static pa_context_flags_t pulse_ctx_flags;
-static pa_proplist *prop_filter;
-
-
static ALCboolean pulse_load(void)
{
ALCboolean ret = ALC_TRUE;
@@ -336,6 +301,15 @@ static ALCboolean pulse_load(void)
return ret;
}
+
+/* Global flags and properties */
+static pa_context_flags_t pulse_ctx_flags;
+static pa_proplist *prop_filter;
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
/* PulseAudio Event Callbacks */
static void context_state_callback(pa_context *context, void *pdata)
{
@@ -357,112 +331,202 @@ static void stream_state_callback(pa_stream *stream, void *pdata)
pa_threaded_mainloop_signal(loop, 0);
}
-static void stream_buffer_attr_callback(pa_stream *stream, void *pdata)
+static void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata)
{
- ALCdevice *device = pdata;
- pulse_data *data = device->ExtraData;
-
- data->attr = *pa_stream_get_buffer_attr(stream);
- TRACE("minreq=%d, tlength=%d, prebuf=%d\n", data->attr.minreq, data->attr.tlength, data->attr.prebuf);
+ pa_threaded_mainloop *loop = pdata;
+ pa_threaded_mainloop_signal(loop, 0);
}
-static void context_state_callback2(pa_context *context, void *pdata)
+static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop)
{
- ALCdevice *Device = pdata;
- pulse_data *data = Device->ExtraData;
-
- if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
+ if(op)
{
- ERR("Received context failure!\n");
- aluHandleDisconnect(Device);
+ while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(loop);
+ pa_operation_unref(op);
}
- pa_threaded_mainloop_signal(data->loop, 0);
}
-static void stream_state_callback2(pa_stream *stream, void *pdata)
+
+static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
{
- ALCdevice *Device = pdata;
- pulse_data *data = Device->ExtraData;
+ const char *name = "OpenAL Soft";
+ char path_name[PATH_MAX];
+ pa_context_state_t state;
+ pa_context *context;
+ int err;
- if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
+ if(pa_get_binary_name(path_name, sizeof(path_name)))
+ name = pa_path_get_filename(path_name);
+
+ context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
+ if(!context)
{
- ERR("Received stream failure!\n");
- aluHandleDisconnect(Device);
+ ERR("pa_context_new() failed\n");
+ return NULL;
}
- pa_threaded_mainloop_signal(data->loop, 0);
-}
-static void stream_success_callback(pa_stream *stream, int success, void *pdata)
-{
- ALCdevice *Device = pdata;
- pulse_data *data = Device->ExtraData;
- (void)stream;
- (void)success;
+ pa_context_set_state_callback(context, context_state_callback, loop);
+
+ if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
+ {
+ while((state=pa_context_get_state(context)) != PA_CONTEXT_READY)
+ {
+ if(!PA_CONTEXT_IS_GOOD(state))
+ {
+ err = pa_context_errno(context);
+ if(err > 0) err = -err;
+ break;
+ }
- pa_threaded_mainloop_signal(data->loop, 0);
+ pa_threaded_mainloop_wait(loop);
+ }
+ }
+ pa_context_set_state_callback(context, NULL, NULL);
+
+ if(err < 0)
+ {
+ if(!silent)
+ ERR("Context did not connect: %s\n", pa_strerror(err));
+ pa_context_unref(context);
+ return NULL;
+ }
+
+ return context;
}
-static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
-{
- ALCdevice *device = pdata;
- pulse_data *data = device->ExtraData;
- char chanmap_str[256] = "";
- const struct {
- const char *str;
- enum DevFmtChannels chans;
- } chanmaps[] = {
- { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
- DevFmtX71 },
- { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
- DevFmtX61 },
- { "front-left,front-right,front-center,lfe,rear-left,rear-right",
- DevFmtX51 },
- { "front-left,front-right,front-center,lfe,side-left,side-right",
- DevFmtX51Side },
- { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
- { "front-left,front-right", DevFmtStereo },
- { "mono", DevFmtMono },
- { NULL, 0 }
- };
- int i;
- (void)context;
- if(eol)
+static ALCboolean pulse_open(pa_threaded_mainloop **loop, pa_context **context,
+ void(*state_cb)(pa_context*,void*), void *ptr)
+{
+ if(!(*loop = pa_threaded_mainloop_new()))
{
- pa_threaded_mainloop_signal(data->loop, 0);
- return;
+ ERR("pa_threaded_mainloop_new() failed!\n");
+ return ALC_FALSE;
+ }
+ if(pa_threaded_mainloop_start(*loop) < 0)
+ {
+ ERR("pa_threaded_mainloop_start() failed\n");
+ goto error;
}
- for(i = 0;chanmaps[i].str;i++)
+ pa_threaded_mainloop_lock(*loop);
+
+ *context = connect_context(*loop, AL_FALSE);
+ if(!*context)
{
- pa_channel_map map;
- if(!pa_channel_map_parse(&map, chanmaps[i].str))
- continue;
+ pa_threaded_mainloop_unlock(*loop);
+ pa_threaded_mainloop_stop(*loop);
+ goto error;
+ }
+ pa_context_set_state_callback(*context, state_cb, ptr);
- if(pa_channel_map_equal(&info->channel_map, &map)
+ pa_threaded_mainloop_unlock(*loop);
+ return ALC_TRUE;
+
+error:
+ pa_threaded_mainloop_free(*loop);
+ *loop = NULL;
+
+ return ALC_FALSE;
+}
+
+static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
+ pa_stream *stream)
+{
+ pa_threaded_mainloop_lock(loop);
+
+ if(stream)
+ {
+ pa_stream_set_moved_callback(stream, NULL, NULL);
#if PA_CHECK_VERSION(0,9,15)
- || (pa_channel_map_superset &&
- pa_channel_map_superset(&info->channel_map, &map))
+ if(pa_stream_set_buffer_attr_callback)
+ pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
#endif
- )
- {
- device->FmtChans = chanmaps[i].chans;
- return;
- }
+ pa_stream_disconnect(stream);
+ pa_stream_unref(stream);
}
- pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
- ERR("Failed to find format for channel map:\n %s\n", chanmap_str);
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+
+ pa_threaded_mainloop_unlock(loop);
+
+ pa_threaded_mainloop_stop(loop);
+ pa_threaded_mainloop_free(loop);
+}
+
+
+typedef struct {
+ char *name;
+ char *device_name;
+} DevMap;
+
+static DevMap *allDevNameMap;
+static ALuint numDevNames;
+static DevMap *allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+
+
+typedef struct ALCpulsePlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ char *device_name;
+
+ pa_buffer_attr attr;
+ pa_sample_spec spec;
+
+ pa_threaded_mainloop *loop;
+
+ pa_stream *stream;
+ pa_context *context;
+
+ volatile ALboolean killNow;
+ althread_t thread;
+} ALCpulsePlayback;
+DECLARE_ALCBACKEND_VTABLE(ALCpulsePlayback);
+
+static void ALCpulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
+static void ALCpulsePlayback_probeDevices(void);
+
+static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata);
+static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata);
+static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata);
+static void ALCpulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
+static void ALCpulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
+static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata);
+static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop,
+ pa_context *context, pa_stream_flags_t flags,
+ pa_buffer_attr *attr, pa_sample_spec *spec,
+ pa_channel_map *chanmap);
+static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr);
+
+static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, void, Destruct)
+static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name);
+static void ALCpulsePlayback_close(ALCpulsePlayback *self);
+static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self);
+static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self);
+static void ALCpulsePlayback_stop(ALCpulsePlayback *self);
+static DECLARE_FORWARD2(ALCpulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, ALCuint, availableSamples)
+static void ALCpulsePlayback_lock(ALCpulsePlayback *self);
+static void ALCpulsePlayback_unlock(ALCpulsePlayback *self);
+
+
+static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCpulsePlayback, ALCbackend, self);
}
-static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
+
+static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
void *temp;
ALuint i;
- (void)context;
-
if(eol)
{
pa_threaded_mainloop_signal(loop, 0);
@@ -487,172 +551,169 @@ static void sink_device_callback(pa_context *context, const pa_sink_info *info,
}
}
-static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata)
+static void ALCpulsePlayback_probeDevices(void)
{
- pa_threaded_mainloop *loop = pdata;
- void *temp;
- ALuint i;
-
- (void)context;
+ pa_threaded_mainloop *loop;
- if(eol)
+ allDevNameMap = malloc(sizeof(DevMap) * 1);
+ if((loop=pa_threaded_mainloop_new()) &&
+ pa_threaded_mainloop_start(loop) >= 0)
{
- pa_threaded_mainloop_signal(loop, 0);
- return;
- }
+ pa_context *context;
- for(i = 0;i < numCaptureDevNames;i++)
- {
- if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0)
- return;
- }
+ pa_threaded_mainloop_lock(loop);
+ context = connect_context(loop, AL_FALSE);
+ if(context)
+ {
+ pa_operation *o;
+ pa_stream_flags_t flags;
+ pa_sample_spec spec;
+ pa_stream *stream;
- TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
+ flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
+ PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
- temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
- if(temp)
- {
- allCaptureDevNameMap = temp;
- allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description);
- allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
- numCaptureDevNames++;
+ spec.format = PA_SAMPLE_S16NE;
+ spec.rate = 44100;
+ spec.channels = 2;
+
+ stream = ALCpulsePlayback_connectStream(NULL, loop, context, flags,
+ NULL, &spec, NULL);
+ if(stream)
+ {
+ o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream),
+ ALCpulsePlayback_deviceCallback, loop);
+ wait_for_operation(o, loop);
+
+ pa_stream_disconnect(stream);
+ pa_stream_unref(stream);
+ stream = NULL;
+ }
+
+ o = pa_context_get_sink_info_list(context, ALCpulsePlayback_deviceCallback, loop);
+ wait_for_operation(o, loop);
+
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+ }
+ pa_threaded_mainloop_unlock(loop);
+ pa_threaded_mainloop_stop(loop);
}
+ if(loop)
+ pa_threaded_mainloop_free(loop);
}
-static void sink_name_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
-{
- ALCdevice *device = pdata;
- pulse_data *data = device->ExtraData;
- (void)context;
- if(eol)
- {
- pa_threaded_mainloop_signal(data->loop, 0);
- return;
- }
+static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata)
+{
+ ALCpulsePlayback *self = pdata;
- free(device->DeviceName);
- device->DeviceName = strdup(info->description);
+ self->attr = *pa_stream_get_buffer_attr(stream);
+ TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf);
}
-static void source_name_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata)
+static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata)
{
- ALCdevice *device = pdata;
- pulse_data *data = device->ExtraData;
- (void)context;
-
- if(eol)
+ ALCpulsePlayback *self = pdata;
+ if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
{
- pa_threaded_mainloop_signal(data->loop, 0);
- return;
+ ERR("Received context failure!\n");
+ aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
}
-
- free(device->DeviceName);
- device->DeviceName = strdup(info->description);
+ pa_threaded_mainloop_signal(self->loop, 0);
}
-
-static void stream_moved_callback(pa_stream *stream, void *pdata)
+static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata)
{
- ALCdevice *device = pdata;
- pulse_data *data = device->ExtraData;
- (void)stream;
-
- free(data->device_name);
- data->device_name = strdup(pa_stream_get_device_name(data->stream));
-
- TRACE("Stream moved to %s\n", data->device_name);
+ ALCpulsePlayback *self = pdata;
+ if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
+ {
+ ERR("Received stream failure!\n");
+ aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+ }
+ pa_threaded_mainloop_signal(self->loop, 0);
}
-
-static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
+static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
- const char *name = "OpenAL Soft";
- char path_name[PATH_MAX];
- pa_context_state_t state;
- pa_context *context;
- int err;
-
- if(pa_get_binary_name(path_name, sizeof(path_name)))
- name = pa_path_get_filename(path_name);
+ ALCpulsePlayback *self = pdata;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ char chanmap_str[256] = "";
+ const struct {
+ const char *str;
+ enum DevFmtChannels chans;
+ } chanmaps[] = {
+ { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
+ DevFmtX71 },
+ { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
+ DevFmtX61 },
+ { "front-left,front-right,front-center,lfe,rear-left,rear-right",
+ DevFmtX51 },
+ { "front-left,front-right,front-center,lfe,side-left,side-right",
+ DevFmtX51Side },
+ { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
+ { "front-left,front-right", DevFmtStereo },
+ { "mono", DevFmtMono },
+ { NULL, 0 }
+ };
+ int i;
- context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
- if(!context)
+ if(eol)
{
- ERR("pa_context_new() failed\n");
- return NULL;
+ pa_threaded_mainloop_signal(self->loop, 0);
+ return;
}
- pa_context_set_state_callback(context, context_state_callback, loop);
-
- if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
+ for(i = 0;chanmaps[i].str;i++)
{
- while((state=pa_context_get_state(context)) != PA_CONTEXT_READY)
- {
- if(!PA_CONTEXT_IS_GOOD(state))
- {
- err = pa_context_errno(context);
- if(err > 0) err = -err;
- break;
- }
+ pa_channel_map map;
+ if(!pa_channel_map_parse(&map, chanmaps[i].str))
+ continue;
- pa_threaded_mainloop_wait(loop);
+ if(pa_channel_map_equal(&info->channel_map, &map)
+#if PA_CHECK_VERSION(0,9,15)
+ || (pa_channel_map_superset &&
+ pa_channel_map_superset(&info->channel_map, &map))
+#endif
+ )
+ {
+ device->FmtChans = chanmaps[i].chans;
+ return;
}
}
- pa_context_set_state_callback(context, NULL, NULL);
- if(err < 0)
- {
- if(!silent)
- ERR("Context did not connect: %s\n", pa_strerror(err));
- pa_context_unref(context);
- return NULL;
- }
-
- return context;
+ pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
+ ERR("Failed to find format for channel map:\n %s\n", chanmap_str);
}
-static pa_stream *connect_playback_stream(const char *device_name,
- pa_threaded_mainloop *loop, pa_context *context,
- pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
- pa_channel_map *chanmap)
+static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
- pa_stream_state_t state;
- pa_stream *stream;
+ ALCpulsePlayback *self = pdata;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
- stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter);
- if(!stream)
+ if(eol)
{
- ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
- return NULL;
+ pa_threaded_mainloop_signal(self->loop, 0);
+ return;
}
- pa_stream_set_state_callback(stream, stream_state_callback, loop);
+ free(device->DeviceName);
+ device->DeviceName = strdup(info->description);
+}
- if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0)
- {
- ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return NULL;
- }
- while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
- {
- if(!PA_STREAM_IS_GOOD(state))
- {
- ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return NULL;
- }
+static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata)
+{
+ ALCpulsePlayback *self = pdata;
- pa_threaded_mainloop_wait(loop);
- }
- pa_stream_set_state_callback(stream, NULL, NULL);
+ free(self->device_name);
+ self->device_name = strdup(pa_stream_get_device_name(stream));
- return stream;
+ TRACE("Stream moved to %s\n", self->device_name);
}
-static pa_stream *connect_record_stream(const char *device_name,
+
+static pa_stream *ALCpulsePlayback_connectStream(const char *device_name,
pa_threaded_mainloop *loop, pa_context *context,
pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
pa_channel_map *chanmap)
@@ -660,7 +721,7 @@ static pa_stream *connect_record_stream(const char *device_name,
pa_stream_state_t state;
pa_stream *stream;
- stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter);
+ stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter);
if(!stream)
{
ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
@@ -669,7 +730,7 @@ static pa_stream *connect_record_stream(const char *device_name,
pa_stream_set_state_callback(stream, stream_state_callback, loop);
- if(pa_stream_connect_record(stream, device_name, attr, flags) < 0)
+ if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0)
{
ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
pa_stream_unref(stream);
@@ -693,137 +754,40 @@ static pa_stream *connect_record_stream(const char *device_name,
}
-static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop)
-{
- if(op)
- {
- while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(loop);
- pa_operation_unref(op);
- }
-}
-
-
-static void probe_devices(ALboolean capture)
-{
- pa_threaded_mainloop *loop;
-
- if(capture == AL_FALSE)
- allDevNameMap = malloc(sizeof(DevMap) * 1);
- else
- allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
-
- if((loop=pa_threaded_mainloop_new()) &&
- pa_threaded_mainloop_start(loop) >= 0)
- {
- pa_context *context;
-
- pa_threaded_mainloop_lock(loop);
- context = connect_context(loop, AL_FALSE);
- if(context)
- {
- pa_operation *o;
-
- if(capture == AL_FALSE)
- {
- pa_stream_flags_t flags;
- pa_sample_spec spec;
- pa_stream *stream;
-
- flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
- PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
-
- spec.format = PA_SAMPLE_S16NE;
- spec.rate = 44100;
- spec.channels = 2;
-
- stream = connect_playback_stream(NULL, loop, context, flags,
- NULL, &spec, NULL);
- if(stream)
- {
- o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop);
- wait_for_operation(o, loop);
-
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = NULL;
- }
-
- o = pa_context_get_sink_info_list(context, sink_device_callback, loop);
- }
- else
- {
- pa_stream_flags_t flags;
- pa_sample_spec spec;
- pa_stream *stream;
-
- flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
- PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
-
- spec.format = PA_SAMPLE_S16NE;
- spec.rate = 44100;
- spec.channels = 1;
-
- stream = connect_record_stream(NULL, loop, context, flags,
- NULL, &spec, NULL);
- if(stream)
- {
- o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop);
- wait_for_operation(o, loop);
-
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = NULL;
- }
-
- o = pa_context_get_source_info_list(context, source_device_callback, loop);
- }
- wait_for_operation(o, loop);
-
- pa_context_disconnect(context);
- pa_context_unref(context);
- }
- pa_threaded_mainloop_unlock(loop);
- pa_threaded_mainloop_stop(loop);
- }
- if(loop)
- pa_threaded_mainloop_free(loop);
-}
-
-
-static ALuint PulseProc(ALvoid *param)
+static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
{
- ALCdevice *Device = param;
- pulse_data *data = Device->ExtraData;
+ ALCpulsePlayback *self = ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
ALuint buffer_size;
ALint update_size;
size_t frame_size;
ssize_t len;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
- pa_threaded_mainloop_lock(data->loop);
- frame_size = pa_frame_size(&data->spec);
- update_size = Device->UpdateSize * frame_size;
+ pa_threaded_mainloop_lock(self->loop);
+ frame_size = pa_frame_size(&self->spec);
+ update_size = device->UpdateSize * frame_size;
/* Sanitize buffer metrics, in case we actually have less than what we
* asked for. */
- buffer_size = minu(update_size*Device->NumUpdates, data->attr.tlength);
+ buffer_size = minu(update_size*device->NumUpdates, self->attr.tlength);
update_size = minu(update_size, buffer_size/2);
do {
- len = pa_stream_writable_size(data->stream) - data->attr.tlength +
+ len = pa_stream_writable_size(self->stream) - self->attr.tlength +
buffer_size;
if(len < update_size)
{
- if(pa_stream_is_corked(data->stream) == 1)
+ if(pa_stream_is_corked(self->stream) == 1)
{
pa_operation *o;
- o = pa_stream_cork(data->stream, 0, NULL, NULL);
+ o = pa_stream_cork(self->stream, 0, NULL, NULL);
if(o) pa_operation_unref(o);
}
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
Sleep(1);
- pa_threaded_mainloop_lock(data->loop);
+ pa_threaded_mainloop_lock(self->loop);
continue;
}
len -= len%update_size;
@@ -836,117 +800,42 @@ static ALuint PulseProc(ALvoid *param)
#if PA_CHECK_VERSION(0,9,16)
if(!pa_stream_begin_write ||
- pa_stream_begin_write(data->stream, &buf, &newlen) < 0)
+ pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
#endif
{
buf = pa_xmalloc(newlen);
free_func = pa_xfree;
}
- aluMixData(Device, buf, newlen/frame_size);
+ aluMixData(device, buf, newlen/frame_size);
- pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
+ pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
len -= newlen;
}
- } while(!data->killNow && Device->Connected);
- pa_threaded_mainloop_unlock(data->loop);
+ } while(!self->killNow && device->Connected);
+ pa_threaded_mainloop_unlock(self->loop);
return 0;
}
-static ALCboolean pulse_open(ALCdevice *device)
-{
- pulse_data *data = pa_xmalloc(sizeof(pulse_data));
- memset(data, 0, sizeof(*data));
-
- if(!(data->loop = pa_threaded_mainloop_new()))
- {
- ERR("pa_threaded_mainloop_new() failed!\n");
- goto out;
- }
- if(pa_threaded_mainloop_start(data->loop) < 0)
- {
- ERR("pa_threaded_mainloop_start() failed\n");
- goto out;
- }
-
- pa_threaded_mainloop_lock(data->loop);
- device->ExtraData = data;
-
- data->context = connect_context(data->loop, AL_FALSE);
- if(!data->context)
- {
- pa_threaded_mainloop_unlock(data->loop);
- goto out;
- }
- pa_context_set_state_callback(data->context, context_state_callback2, device);
-
- pa_threaded_mainloop_unlock(data->loop);
- return ALC_TRUE;
-
-out:
- if(data->loop)
- {
- pa_threaded_mainloop_stop(data->loop);
- pa_threaded_mainloop_free(data->loop);
- }
-
- device->ExtraData = NULL;
- pa_xfree(data);
- return ALC_FALSE;
-}
-
-static void pulse_close(ALCdevice *device)
-{
- pulse_data *data = device->ExtraData;
-
- pa_threaded_mainloop_lock(data->loop);
-
- if(data->stream)
- {
- pa_stream_set_moved_callback(data->stream, NULL, NULL);
-#if PA_CHECK_VERSION(0,9,15)
- if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
-#endif
- pa_stream_disconnect(data->stream);
- pa_stream_unref(data->stream);
- }
-
- pa_context_disconnect(data->context);
- pa_context_unref(data->context);
-
- pa_threaded_mainloop_unlock(data->loop);
-
- pa_threaded_mainloop_stop(data->loop);
- pa_threaded_mainloop_free(data->loop);
-
- free(data->device_name);
-
- device->ExtraData = NULL;
- pa_xfree(data);
-}
-
-/* OpenAL */
-static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name)
+static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name)
{
const char *pulse_name = NULL;
pa_stream_flags_t flags;
pa_sample_spec spec;
- pulse_data *data;
pa_operation *o;
- if(device_name)
+ if(name)
{
ALuint i;
if(!allDevNameMap)
- probe_devices(AL_FALSE);
+ ALCpulsePlayback_probeDevices();
for(i = 0;i < numDevNames;i++)
{
- if(strcmp(device_name, allDevNameMap[i].name) == 0)
+ if(strcmp(name, allDevNameMap[i].name) == 0)
{
pulse_name = allDevNameMap[i].device_name;
break;
@@ -956,11 +845,10 @@ static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name
return ALC_INVALID_VALUE;
}
- if(pulse_open(device) == ALC_FALSE)
+ if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self))
return ALC_INVALID_VALUE;
- data = device->ExtraData;
- pa_threaded_mainloop_lock(data->loop);
+ pa_threaded_mainloop_lock(self->loop);
flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
PA_STREAM_FIX_CHANNELS;
@@ -971,58 +859,67 @@ static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name
spec.rate = 44100;
spec.channels = 2;
- data->stream = connect_playback_stream(pulse_name, data->loop, data->context,
- flags, NULL, &spec, NULL);
- if(!data->stream)
+ self->stream = ALCpulsePlayback_connectStream(pulse_name, self->loop, self->context,
+ flags, NULL, &spec, NULL);
+ if(!self->stream)
{
- pa_threaded_mainloop_unlock(data->loop);
- pulse_close(device);
+ pa_threaded_mainloop_unlock(self->loop);
+ pulse_close(self->loop, self->context, self->stream);
+ self->loop = NULL;
+ self->context = NULL;
return ALC_INVALID_VALUE;
}
+ pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
- data->device_name = strdup(pa_stream_get_device_name(data->stream));
- o = pa_context_get_sink_info_by_name(data->context, data->device_name,
- sink_name_callback, device);
- wait_for_operation(o, data->loop);
-
- pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
+ self->device_name = strdup(pa_stream_get_device_name(self->stream));
+ o = pa_context_get_sink_info_by_name(self->context, self->device_name,
+ ALCpulsePlayback_sinkNameCallback, self);
+ wait_for_operation(o, self->loop);
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_NO_ERROR;
}
-static void pulse_close_playback(ALCdevice *device)
+static void ALCpulsePlayback_close(ALCpulsePlayback *self)
{
- pulse_close(device);
+ pulse_close(self->loop, self->context, self->stream);
+ self->loop = NULL;
+ self->context = NULL;
+ self->stream = NULL;
+
+ free(self->device_name);
+ self->device_name = NULL;
}
-static ALCboolean pulse_reset_playback(ALCdevice *device)
+static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
{
- pulse_data *data = device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
pa_stream_flags_t flags = 0;
pa_channel_map chanmap;
+ const char *mapname;
ALuint len;
- pa_threaded_mainloop_lock(data->loop);
+ pa_threaded_mainloop_lock(self->loop);
- if(data->stream)
+ if(self->stream)
{
- pa_stream_set_moved_callback(data->stream, NULL, NULL);
+ pa_stream_set_moved_callback(self->stream, NULL, NULL);
#if PA_CHECK_VERSION(0,9,15)
if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
+ pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
#endif
- pa_stream_disconnect(data->stream);
- pa_stream_unref(data->stream);
- data->stream = NULL;
+ pa_stream_disconnect(self->stream);
+ pa_stream_unref(self->stream);
+ self->stream = NULL;
}
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
pa_operation *o;
- o = pa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
- wait_for_operation(o, data->loop);
+ o = pa_context_get_sink_info_by_name(self->context, self->device_name,
+ ALCpulsePlayback_sinkInfoCallback, self);
+ wait_for_operation(o, self->loop);
}
if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
flags |= PA_STREAM_FIX_RATE;
@@ -1039,152 +936,434 @@ static ALCboolean pulse_reset_playback(ALCdevice *device)
device->FmtType = DevFmtUByte;
/* fall-through */
case DevFmtUByte:
- data->spec.format = PA_SAMPLE_U8;
+ self->spec.format = PA_SAMPLE_U8;
break;
case DevFmtUShort:
device->FmtType = DevFmtShort;
/* fall-through */
case DevFmtShort:
- data->spec.format = PA_SAMPLE_S16NE;
+ self->spec.format = PA_SAMPLE_S16NE;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
/* fall-through */
case DevFmtInt:
- data->spec.format = PA_SAMPLE_S32NE;
+ self->spec.format = PA_SAMPLE_S32NE;
break;
case DevFmtFloat:
- data->spec.format = PA_SAMPLE_FLOAT32NE;
+ self->spec.format = PA_SAMPLE_FLOAT32NE;
break;
}
- data->spec.rate = device->Frequency;
- data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+ self->spec.rate = device->Frequency;
+ self->spec.channels = ChannelsFromDevFmt(device->FmtChans);
- if(pa_sample_spec_valid(&data->spec) == 0)
+ if(pa_sample_spec_valid(&self->spec) == 0)
{
ERR("Invalid sample format\n");
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_FALSE;
}
- if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+ mapname = "(invalid)";
+ switch(device->FmtChans)
{
- ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
- pa_threaded_mainloop_unlock(data->loop);
+ case DevFmtMono:
+ mapname = "mono";
+ break;
+ case DevFmtStereo:
+ mapname = "front-left,front-right";
+ break;
+ case DevFmtQuad:
+ mapname = "front-left,front-right,rear-left,rear-right";
+ break;
+ case DevFmtX51:
+ mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
+ break;
+ case DevFmtX51Side:
+ mapname = "front-left,front-right,front-center,lfe,side-left,side-right";
+ break;
+ case DevFmtX61:
+ mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right";
+ break;
+ case DevFmtX71:
+ mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right";
+ break;
+ }
+ if(!pa_channel_map_parse(&chanmap, mapname))
+ {
+ ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans));
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_FALSE;
}
SetDefaultWFXChannelOrder(device);
- data->attr.fragsize = -1;
- data->attr.prebuf = 0;
- data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec);
- data->attr.tlength = data->attr.minreq * maxu(device->NumUpdates, 2);
- data->attr.maxlength = -1;
+ self->attr.fragsize = -1;
+ self->attr.prebuf = 0;
+ self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec);
+ self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2);
+ self->attr.maxlength = -1;
- data->stream = connect_playback_stream(data->device_name, data->loop,
- data->context, flags, &data->attr,
- &data->spec, &chanmap);
- if(!data->stream)
+ self->stream = ALCpulsePlayback_connectStream(self->device_name, self->loop,
+ self->context, flags, &self->attr,
+ &self->spec, &chanmap);
+ if(!self->stream)
{
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_FALSE;
}
- pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+ pa_stream_set_state_callback(self->stream, ALCpulsePlayback_streamStateCallback, self);
+ pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
- data->spec = *(pa_stream_get_sample_spec(data->stream));
- if(device->Frequency != data->spec.rate)
+ self->spec = *(pa_stream_get_sample_spec(self->stream));
+ if(device->Frequency != self->spec.rate)
{
pa_operation *o;
/* Server updated our playback rate, so modify the buffer attribs
* accordingly. */
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
- data->spec.rate + 0.5);
- data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec);
- data->attr.tlength = data->attr.minreq * clampu(device->NumUpdates, 2, 16);
- data->attr.maxlength = -1;
- data->attr.prebuf = 0;
+ self->spec.rate + 0.5);
+ self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec);
+ self->attr.tlength = self->attr.minreq * clampu(device->NumUpdates, 2, 16);
+ self->attr.maxlength = -1;
+ self->attr.prebuf = 0;
- o = pa_stream_set_buffer_attr(data->stream, &data->attr,
- stream_success_callback, device);
- wait_for_operation(o, data->loop);
+ o = pa_stream_set_buffer_attr(self->stream, &self->attr,
+ stream_success_callback, self->loop);
+ wait_for_operation(o, self->loop);
- device->Frequency = data->spec.rate;
+ device->Frequency = self->spec.rate;
}
- pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
#if PA_CHECK_VERSION(0,9,15)
if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
+ pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
#endif
- stream_buffer_attr_callback(data->stream, device);
+ ALCpulsePlayback_bufferAttrCallback(self->stream, self);
- len = data->attr.minreq / pa_frame_size(&data->spec);
+ len = self->attr.minreq / pa_frame_size(&self->spec);
if((CPUCapFlags&CPU_CAP_SSE))
len = (len+3)&~3;
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
device->NumUpdates = clampu(device->NumUpdates, 2, 16);
device->UpdateSize = len;
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_TRUE;
}
-static ALCboolean pulse_start_playback(ALCdevice *device)
+static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
{
- pulse_data *data = device->ExtraData;
-
- data->thread = StartThread(PulseProc, device);
- if(!data->thread)
+ if(!StartThread(&self->thread, ALCpulsePlayback_mixerProc, self))
return ALC_FALSE;
-
return ALC_TRUE;
}
-static void pulse_stop_playback(ALCdevice *device)
+static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
{
- pulse_data *data = device->ExtraData;
pa_operation *o;
- if(!data->stream)
+ if(!self->stream)
return;
- data->killNow = AL_TRUE;
- if(data->thread)
+ self->killNow = AL_TRUE;
+ if(self->thread)
+ {
+ StopThread(self->thread);
+ self->thread = NULL;
+ }
+ self->killNow = AL_FALSE;
+
+ pa_threaded_mainloop_lock(self->loop);
+
+ o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop);
+ wait_for_operation(o, self->loop);
+
+ pa_threaded_mainloop_unlock(self->loop);
+}
+
+
+static void ALCpulsePlayback_lock(ALCpulsePlayback *self)
+{
+ pa_threaded_mainloop_lock(self->loop);
+}
+
+static void ALCpulsePlayback_unlock(ALCpulsePlayback *self)
+{
+ pa_threaded_mainloop_unlock(self->loop);
+}
+
+
+static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self)
+{
+ pa_usec_t latency = 0;
+ int neg;
+
+ if(pa_stream_get_latency(self->stream, &latency, &neg) != 0)
{
- StopThread(data->thread);
- data->thread = NULL;
+ ERR("Failed to get stream latency!\n");
+ return 0;
}
- data->killNow = AL_FALSE;
- pa_threaded_mainloop_lock(data->loop);
+ if(neg) latency = 0;
+ return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
+}
- o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
- wait_for_operation(o, data->loop);
- pa_threaded_mainloop_unlock(data->loop);
+static void ALCpulsePlayback_Delete(ALCpulsePlayback *self)
+{
+ free(self);
}
+DEFINE_ALCBACKEND_VTABLE(ALCpulsePlayback);
+
+
+typedef struct ALCpulseCapture {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ char *device_name;
+
+ const void *cap_store;
+ size_t cap_len;
+ size_t cap_remain;
+
+ ALCuint last_readable;
+
+ pa_buffer_attr attr;
+ pa_sample_spec spec;
-static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
+ pa_threaded_mainloop *loop;
+
+ pa_stream *stream;
+ pa_context *context;
+} ALCpulseCapture;
+DECLARE_ALCBACKEND_VTABLE(ALCpulseCapture);
+
+static void ALCpulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
+static void ALCpulseCapture_probeDevices(void);
+
+static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdata);
+static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata);
+static void ALCpulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
+static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata);
+static pa_stream *ALCpulseCapture_connectStream(const char *device_name,
+ pa_threaded_mainloop *loop, pa_context *context,
+ pa_stream_flags_t flags, pa_buffer_attr *attr,
+ pa_sample_spec *spec, pa_channel_map *chanmap);
+
+static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, void, Destruct)
+static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name);
+static void ALCpulseCapture_close(ALCpulseCapture *self);
+static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self);
+static void ALCpulseCapture_stop(ALCpulseCapture *self);
+static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self);
+static void ALCpulseCapture_lock(ALCpulseCapture *self);
+static void ALCpulseCapture_unlock(ALCpulseCapture *self);
+
+
+static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device)
{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCpulseCapture, ALCbackend, self);
+}
+
+
+static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
+{
+ pa_threaded_mainloop *loop = pdata;
+ void *temp;
+ ALuint i;
+
+ if(eol)
+ {
+ pa_threaded_mainloop_signal(loop, 0);
+ return;
+ }
+
+ for(i = 0;i < numCaptureDevNames;i++)
+ {
+ if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0)
+ return;
+ }
+
+ TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
+
+ temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
+ if(temp)
+ {
+ allCaptureDevNameMap = temp;
+ allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description);
+ allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
+ numCaptureDevNames++;
+ }
+}
+
+static void ALCpulseCapture_probeDevices(void)
+{
+ pa_threaded_mainloop *loop;
+
+ allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
+ if((loop=pa_threaded_mainloop_new()) &&
+ pa_threaded_mainloop_start(loop) >= 0)
+ {
+ pa_context *context;
+
+ pa_threaded_mainloop_lock(loop);
+ context = connect_context(loop, AL_FALSE);
+ if(context)
+ {
+ pa_operation *o;
+ pa_stream_flags_t flags;
+ pa_sample_spec spec;
+ pa_stream *stream;
+
+ flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
+ PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
+
+ spec.format = PA_SAMPLE_S16NE;
+ spec.rate = 44100;
+ spec.channels = 1;
+
+ stream = ALCpulseCapture_connectStream(NULL, loop, context, flags,
+ NULL, &spec, NULL);
+ if(stream)
+ {
+ o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream),
+ ALCpulseCapture_deviceCallback, loop);
+ wait_for_operation(o, loop);
+
+ pa_stream_disconnect(stream);
+ pa_stream_unref(stream);
+ stream = NULL;
+ }
+
+ o = pa_context_get_source_info_list(context, ALCpulseCapture_deviceCallback, loop);
+ wait_for_operation(o, loop);
+
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+ }
+ pa_threaded_mainloop_unlock(loop);
+ pa_threaded_mainloop_stop(loop);
+ }
+ if(loop)
+ pa_threaded_mainloop_free(loop);
+}
+
+
+static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdata)
+{
+ ALCpulseCapture *self = pdata;
+ if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
+ {
+ ERR("Received context failure!\n");
+ aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+ }
+ pa_threaded_mainloop_signal(self->loop, 0);
+}
+
+static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata)
+{
+ ALCpulseCapture *self = pdata;
+ if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
+ {
+ ERR("Received stream failure!\n");
+ aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+ }
+ pa_threaded_mainloop_signal(self->loop, 0);
+}
+
+
+static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
+{
+ ALCpulseCapture *self = pdata;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+
+ if(eol)
+ {
+ pa_threaded_mainloop_signal(self->loop, 0);
+ return;
+ }
+
+ free(device->DeviceName);
+ device->DeviceName = strdup(info->description);
+}
+
+
+static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata)
+{
+ ALCpulseCapture *self = pdata;
+
+ free(self->device_name);
+ self->device_name = strdup(pa_stream_get_device_name(stream));
+
+ TRACE("Stream moved to %s\n", self->device_name);
+}
+
+
+static pa_stream *ALCpulseCapture_connectStream(const char *device_name,
+ pa_threaded_mainloop *loop, pa_context *context,
+ pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
+ pa_channel_map *chanmap)
+{
+ pa_stream_state_t state;
+ pa_stream *stream;
+
+ stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter);
+ if(!stream)
+ {
+ ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
+ return NULL;
+ }
+
+ pa_stream_set_state_callback(stream, stream_state_callback, loop);
+
+ if(pa_stream_connect_record(stream, device_name, attr, flags) < 0)
+ {
+ ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
+ pa_stream_unref(stream);
+ return NULL;
+ }
+
+ while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
+ {
+ if(!PA_STREAM_IS_GOOD(state))
+ {
+ ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
+ pa_stream_unref(stream);
+ return NULL;
+ }
+
+ pa_threaded_mainloop_wait(loop);
+ }
+ pa_stream_set_state_callback(stream, NULL, NULL);
+
+ return stream;
+}
+
+
+static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
const char *pulse_name = NULL;
pa_stream_flags_t flags = 0;
pa_channel_map chanmap;
- pulse_data *data;
pa_operation *o;
ALuint samples;
- if(device_name)
+ if(name)
{
ALuint i;
if(!allCaptureDevNameMap)
- probe_devices(AL_TRUE);
+ ALCpulseCapture_probeDevices();
for(i = 0;i < numCaptureDevNames;i++)
{
- if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
+ if(strcmp(name, allCaptureDevNameMap[i].name) == 0)
{
pulse_name = allCaptureDevNameMap[i].device_name;
break;
@@ -1194,158 +1373,164 @@ static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
return ALC_INVALID_VALUE;
}
- if(pulse_open(device) == ALC_FALSE)
+ if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
return ALC_INVALID_VALUE;
- data = device->ExtraData;
- pa_threaded_mainloop_lock(data->loop);
+ pa_threaded_mainloop_lock(self->loop);
- data->spec.rate = device->Frequency;
- data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+ self->spec.rate = device->Frequency;
+ self->spec.channels = ChannelsFromDevFmt(device->FmtChans);
switch(device->FmtType)
{
case DevFmtUByte:
- data->spec.format = PA_SAMPLE_U8;
+ self->spec.format = PA_SAMPLE_U8;
break;
case DevFmtShort:
- data->spec.format = PA_SAMPLE_S16NE;
+ self->spec.format = PA_SAMPLE_S16NE;
break;
case DevFmtInt:
- data->spec.format = PA_SAMPLE_S32NE;
+ self->spec.format = PA_SAMPLE_S32NE;
break;
case DevFmtFloat:
- data->spec.format = PA_SAMPLE_FLOAT32NE;
+ self->spec.format = PA_SAMPLE_FLOAT32NE;
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
goto fail;
}
- if(pa_sample_spec_valid(&data->spec) == 0)
+ if(pa_sample_spec_valid(&self->spec) == 0)
{
ERR("Invalid sample format\n");
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
goto fail;
}
- if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+ if(!pa_channel_map_init_auto(&chanmap, self->spec.channels, PA_CHANNEL_MAP_WAVEEX))
{
- ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
- pa_threaded_mainloop_unlock(data->loop);
+ ERR("Couldn't build map for channel count (%d)!\n", self->spec.channels);
+ pa_threaded_mainloop_unlock(self->loop);
goto fail;
}
samples = device->UpdateSize * device->NumUpdates;
samples = maxu(samples, 100 * device->Frequency / 1000);
- data->attr.minreq = -1;
- data->attr.prebuf = -1;
- data->attr.maxlength = samples * pa_frame_size(&data->spec);
- data->attr.tlength = -1;
- data->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
- pa_frame_size(&data->spec);
+ self->attr.minreq = -1;
+ self->attr.prebuf = -1;
+ self->attr.maxlength = samples * pa_frame_size(&self->spec);
+ self->attr.tlength = -1;
+ self->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
+ pa_frame_size(&self->spec);
flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
if(!GetConfigValueBool("pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
- data->stream = connect_record_stream(pulse_name, data->loop, data->context,
- flags, &data->attr, &data->spec,
- &chanmap);
- if(!data->stream)
+ self->stream = ALCpulseCapture_connectStream(pulse_name, self->loop, self->context,
+ flags, &self->attr, &self->spec,
+ &chanmap);
+ if(!self->stream)
{
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
goto fail;
}
- pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+ pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self);
+ pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
- data->device_name = strdup(pa_stream_get_device_name(data->stream));
- o = pa_context_get_source_info_by_name(data->context, data->device_name,
- source_name_callback, device);
- wait_for_operation(o, data->loop);
+ self->device_name = strdup(pa_stream_get_device_name(self->stream));
+ o = pa_context_get_source_info_by_name(self->context, self->device_name,
+ ALCpulseCapture_sourceNameCallback, self);
+ wait_for_operation(o, self->loop);
- pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
-
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
return ALC_NO_ERROR;
fail:
- pulse_close(device);
+ pulse_close(self->loop, self->context, self->stream);
+ self->loop = NULL;
+ self->context = NULL;
+ self->stream = NULL;
+
return ALC_INVALID_VALUE;
}
-static void pulse_close_capture(ALCdevice *device)
+static void ALCpulseCapture_close(ALCpulseCapture *self)
{
- pulse_close(device);
+ pulse_close(self->loop, self->context, self->stream);
+ self->loop = NULL;
+ self->context = NULL;
+ self->stream = NULL;
+
+ free(self->device_name);
+ self->device_name = NULL;
}
-static void pulse_start_capture(ALCdevice *device)
+static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
pa_operation *o;
+ o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop);
+ wait_for_operation(o, self->loop);
- o = pa_stream_cork(data->stream, 0, stream_success_callback, device);
- wait_for_operation(o, data->loop);
+ return ALC_TRUE;
}
-static void pulse_stop_capture(ALCdevice *device)
+static void ALCpulseCapture_stop(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
pa_operation *o;
-
- o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
- wait_for_operation(o, data->loop);
+ o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop);
+ wait_for_operation(o, self->loop);
}
-static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples)
{
- pulse_data *data = device->ExtraData;
- ALCuint todo = samples * pa_frame_size(&data->spec);
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ ALCuint todo = samples * pa_frame_size(&self->spec);
/* Capture is done in fragment-sized chunks, so we loop until we get all
* that's available */
- data->last_readable -= todo;
+ self->last_readable -= todo;
while(todo > 0)
{
size_t rem = todo;
- if(data->cap_len == 0)
+ if(self->cap_len == 0)
{
pa_stream_state_t state;
- state = pa_stream_get_state(data->stream);
+ state = pa_stream_get_state(self->stream);
if(!PA_STREAM_IS_GOOD(state))
{
aluHandleDisconnect(device);
break;
}
- if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0)
+ if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0)
{
ERR("pa_stream_peek() failed: %s\n",
- pa_strerror(pa_context_errno(data->context)));
+ pa_strerror(pa_context_errno(self->context)));
aluHandleDisconnect(device);
break;
}
- data->cap_remain = data->cap_len;
+ self->cap_remain = self->cap_len;
}
- if(rem > data->cap_remain)
- rem = data->cap_remain;
+ if(rem > self->cap_remain)
+ rem = self->cap_remain;
- memcpy(buffer, data->cap_store, rem);
+ memcpy(buffer, self->cap_store, rem);
buffer = (ALbyte*)buffer + rem;
todo -= rem;
- data->cap_store = (ALbyte*)data->cap_store + rem;
- data->cap_remain -= rem;
- if(data->cap_remain == 0)
+ self->cap_store = (ALbyte*)self->cap_store + rem;
+ self->cap_remain -= rem;
+ if(self->cap_remain == 0)
{
- pa_stream_drop(data->stream);
- data->cap_len = 0;
+ pa_stream_drop(self->stream);
+ self->cap_len = 0;
}
}
if(todo > 0)
@@ -1354,77 +1539,70 @@ static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint
return ALC_NO_ERROR;
}
-static ALCuint pulse_available_samples(ALCdevice *device)
+static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
- size_t readable = data->cap_remain;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ size_t readable = self->cap_remain;
if(device->Connected)
{
- ssize_t got = pa_stream_readable_size(data->stream);
+ ssize_t got = pa_stream_readable_size(self->stream);
if(got < 0)
{
ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
aluHandleDisconnect(device);
}
- else if((size_t)got > data->cap_len)
- readable += got - data->cap_len;
+ else if((size_t)got > self->cap_len)
+ readable += got - self->cap_len;
}
- if(data->last_readable < readable)
- data->last_readable = readable;
- return data->last_readable / pa_frame_size(&data->spec);
+ if(self->last_readable < readable)
+ self->last_readable = readable;
+ return self->last_readable / pa_frame_size(&self->spec);
}
-static void pulse_lock(ALCdevice *device)
+static void ALCpulseCapture_lock(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
- pa_threaded_mainloop_lock(data->loop);
+ pa_threaded_mainloop_lock(self->loop);
}
-static void pulse_unlock(ALCdevice *device)
+static void ALCpulseCapture_unlock(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
- pa_threaded_mainloop_unlock(data->loop);
+ pa_threaded_mainloop_unlock(self->loop);
}
-static ALint64 pulse_get_latency(ALCdevice *device)
+static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self)
{
- pulse_data *data = device->ExtraData;
pa_usec_t latency = 0;
int neg;
- if(pa_stream_get_latency(data->stream, &latency, &neg) == 0)
+ if(pa_stream_get_latency(self->stream, &latency, &neg) != 0)
{
- if(neg)
- latency = 0;
- return (ALint64)minu64(latency, MAKEU64(0x7fffffff,0xffffffff)/1000) * 1000;
+ ERR("Failed to get stream latency!\n");
+ return 0;
}
- ERR("Failed to get stream latency!\n");
- return 0;
+
+ if(neg) latency = 0;
+ return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
}
-static const BackendFuncs pulse_funcs = {
- pulse_open_playback,
- pulse_close_playback,
- pulse_reset_playback,
- pulse_start_playback,
- pulse_stop_playback,
- pulse_open_capture,
- pulse_close_capture,
- pulse_start_capture,
- pulse_stop_capture,
- pulse_capture_samples,
- pulse_available_samples,
- pulse_lock,
- pulse_unlock,
- pulse_get_latency
-};
-
-ALCboolean alc_pulse_init(BackendFuncs *func_list)
+static void ALCpulseCapture_Delete(ALCpulseCapture *self)
+{
+ free(self);
+}
+
+DEFINE_ALCBACKEND_VTABLE(ALCpulseCapture);
+
+
+typedef struct ALCpulseBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCpulseBackendFactory;
+#define ALCPULSEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self))
{
ALCboolean ret = ALC_FALSE;
@@ -1445,7 +1623,6 @@ ALCboolean alc_pulse_init(BackendFuncs *func_list)
context = connect_context(loop, AL_TRUE);
if(context)
{
- *func_list = pulse_funcs;
ret = ALC_TRUE;
/* Some libraries (Phonon, Qt) set some pulseaudio properties
@@ -1469,7 +1646,7 @@ ALCboolean alc_pulse_init(BackendFuncs *func_list)
return ret;
}
-void alc_pulse_deinit(void)
+static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self))
{
ALuint i;
@@ -1498,7 +1675,14 @@ void alc_pulse_deinit(void)
/* PulseAudio doesn't like being CloseLib'd sometimes */
}
-void alc_pulse_probe(enum DevProbe type)
+static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type)
{
ALuint i;
@@ -1514,7 +1698,7 @@ void alc_pulse_probe(enum DevProbe type)
allDevNameMap = NULL;
numDevNames = 0;
- probe_devices(AL_FALSE);
+ ALCpulsePlayback_probeDevices();
for(i = 0;i < numDevNames;i++)
AppendAllDevicesList(allDevNameMap[i].name);
@@ -1530,7 +1714,7 @@ void alc_pulse_probe(enum DevProbe type)
allCaptureDevNameMap = NULL;
numCaptureDevNames = 0;
- probe_devices(AL_TRUE);
+ ALCpulseCapture_probeDevices();
for(i = 0;i < numCaptureDevNames;i++)
AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
@@ -1538,17 +1722,75 @@ void alc_pulse_probe(enum DevProbe type)
}
}
-#else
+static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCpulsePlayback *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCpulsePlayback_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCpulseCapture *backend;
+
+ backend = calloc(1, sizeof(*backend));
+ if(!backend) return NULL;
+
+ ALCpulseCapture_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
+
+
+#else /* PA_API_VERSION == 12 */
#warning "Unsupported API version, backend will be unavailable!"
-ALCboolean alc_pulse_init(BackendFuncs *func_list)
-{ return ALC_FALSE; (void)func_list; }
+typedef struct ALCpulseBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCpulseBackendFactory;
+#define ALCPULSEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } }
-void alc_pulse_deinit(void)
-{ }
+static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self))
+{
+ return ALC_FALSE;
+}
-void alc_pulse_probe(enum DevProbe type)
-{ (void)type; }
+static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self))
+{
+}
-#endif
+static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type))
+{
+ return ALC_FALSE;
+}
+
+static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type))
+{
+}
+
+static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type))
+{
+ return NULL;
+}
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
+
+#endif /* PA_API_VERSION == 12 */
+
+ALCbackendFactory *ALCpulseBackendFactory_getFactory(void)
+{
+ static ALCpulseBackendFactory factory = ALCPULSEBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c
new file mode 100644
index 00000000..c9762f85
--- /dev/null
+++ b/Alc/backends/qsa.c
@@ -0,0 +1,1169 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2011-2013 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+#include <errno.h>
+#include <memory.h>
+#include <sys/select.h>
+#include <sys/asoundlib.h>
+#include <sys/neutrino.h>
+
+#include "alMain.h"
+#include "alu.h"
+#include "threads.h"
+
+
+typedef struct
+{
+ snd_pcm_t* pcmHandle;
+ int audio_fd;
+
+ snd_pcm_channel_setup_t csetup;
+ snd_pcm_channel_params_t cparams;
+
+ ALvoid* buffer;
+ ALsizei size;
+
+ volatile int killNow;
+ althread_t thread;
+} qsa_data;
+
+typedef struct
+{
+ ALCchar* name;
+ int card;
+ int dev;
+} DevMap;
+
+static const ALCchar qsaDevice[]="QSA Default";
+static DevMap* allDevNameMap;
+static ALuint numDevNames;
+static DevMap* allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+
+static const struct
+{
+ int32_t format;
+} formatlist[]=
+{
+ {SND_PCM_SFMT_FLOAT_LE},
+ {SND_PCM_SFMT_S32_LE},
+ {SND_PCM_SFMT_U32_LE},
+ {SND_PCM_SFMT_S16_LE},
+ {SND_PCM_SFMT_U16_LE},
+ {SND_PCM_SFMT_S8},
+ {SND_PCM_SFMT_U8},
+ {0},
+};
+
+static const struct
+{
+ int32_t rate;
+} ratelist[]=
+{
+ {192000},
+ {176400},
+ {96000},
+ {88200},
+ {48000},
+ {44100},
+ {32000},
+ {24000},
+ {22050},
+ {16000},
+ {12000},
+ {11025},
+ {8000},
+ {0},
+};
+
+static const struct
+{
+ int32_t channels;
+} channellist[]=
+{
+ {8},
+ {7},
+ {6},
+ {4},
+ {2},
+ {1},
+ {0},
+};
+
+static DevMap* deviceList(int type, ALuint* count)
+{
+ snd_ctl_t* handle;
+ snd_pcm_info_t pcminfo;
+ int max_cards, card, err, dev, num_devices, idx;
+ DevMap* dev_list;
+ char name[1024];
+ struct snd_ctl_hw_info info;
+ void* temp;
+
+ idx=0;
+ num_devices=0;
+ max_cards=snd_cards();
+
+ if (max_cards<=0)
+ {
+ return 0;
+ }
+
+ dev_list=malloc(sizeof(DevMap)*1);
+ dev_list[0].name=strdup(qsaDevice);
+ num_devices=1;
+
+ for (card=0; card<max_cards; card++)
+ {
+ if ((err=snd_ctl_open(&handle, card))<0)
+ {
+ continue;
+ }
+ if ((err=snd_ctl_hw_info(handle, &info))<0)
+ {
+ snd_ctl_close(handle);
+ continue;
+ }
+
+ for (dev=0; dev<(int)info.pcmdevs; dev++)
+ {
+ if ((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
+ {
+ continue;
+ }
+
+ if ((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
+ (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
+ {
+ temp=realloc(dev_list, sizeof(DevMap)*(num_devices+1));
+ if (temp)
+ {
+ dev_list=temp;
+ snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
+ dev_list[num_devices].name=strdup(name);
+ dev_list[num_devices].card=card;
+ dev_list[num_devices].dev=dev;
+ num_devices++;
+ }
+ }
+ }
+ snd_ctl_close (handle);
+ }
+
+ *count=num_devices;
+
+ return dev_list;
+}
+
+
+FORCE_ALIGN static ALuint qsa_proc_playback(ALvoid* ptr)
+{
+ ALCdevice* device=(ALCdevice*)ptr;
+ qsa_data* data=(qsa_data*)device->ExtraData;
+ char* write_ptr;
+ int avail;
+ snd_pcm_channel_status_t status;
+ struct sched_param param;
+ fd_set wfds;
+ int selectret;
+ struct timeval timeout;
+
+ SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
+
+ /* Increase default 10 priority to 11 to avoid jerky sound */
+ SchedGet(0, 0, &param);
+ param.sched_priority=param.sched_curpriority+1;
+ SchedSet(0, 0, SCHED_NOCHANGE, &param);
+
+ ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+ while (!data->killNow)
+ {
+ ALint len=data->size;
+ write_ptr=data->buffer;
+
+ avail=len/frame_size;
+ aluMixData(device, write_ptr, avail);
+
+ while (len>0 && !data->killNow)
+ {
+ FD_ZERO(&wfds);
+ FD_SET(data->audio_fd, &wfds);
+ timeout.tv_sec=2;
+ timeout.tv_usec=0;
+
+ /* Select also works like time slice to OS */
+ selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
+ switch (selectret)
+ {
+ case -1:
+ aluHandleDisconnect(device);
+ return 1;
+ case 0:
+ break;
+ default:
+ if (FD_ISSET(data->audio_fd, &wfds))
+ {
+ break;
+ }
+ break;
+ }
+
+ int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
+
+ if (wrote<=0)
+ {
+ if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
+ {
+ continue;
+ }
+
+ memset(&status, 0, sizeof (status));
+ status.channel=SND_PCM_CHANNEL_PLAYBACK;
+
+ snd_pcm_plugin_status(data->pcmHandle, &status);
+
+ /* we need to reinitialize the sound channel if we've underrun the buffer */
+ if ((status.status==SND_PCM_STATUS_UNDERRUN) ||
+ (status.status==SND_PCM_STATUS_READY))
+ {
+ if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
+ {
+ aluHandleDisconnect(device);
+ break;
+ }
+ }
+ }
+ else
+ {
+ write_ptr+=wrote;
+ len-=wrote;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/************/
+/* Playback */
+/************/
+
+static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
+{
+ qsa_data* data;
+ char driver[64];
+ int status;
+ int card, dev;
+
+ strncpy(driver, GetConfigValue("qsa", "device", qsaDevice), sizeof(driver)-1);
+ driver[sizeof(driver)-1]=0;
+
+ data=(qsa_data*)calloc(1, sizeof(qsa_data));
+ if (data==NULL)
+ {
+ return ALC_OUT_OF_MEMORY;
+ }
+
+ if (!deviceName)
+ {
+ deviceName=driver;
+ }
+
+ if (strcmp(deviceName, qsaDevice)==0)
+ {
+ if (!deviceName)
+ {
+ deviceName=qsaDevice;
+ }
+
+ status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
+ }
+ else
+ {
+ size_t idx;
+
+ if (!allDevNameMap)
+ {
+ allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
+ }
+
+ for (idx=0; idx<numDevNames; idx++)
+ {
+ if (allDevNameMap[idx].name && strcmp(deviceName, allDevNameMap[idx].name)==0)
+ {
+ if (idx>0)
+ {
+ break;
+ }
+ }
+ }
+ if (idx==numDevNames)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ status=snd_pcm_open(&data->pcmHandle, allDevNameMap[idx].card, allDevNameMap[idx].dev, SND_PCM_OPEN_PLAYBACK);
+ }
+
+ if (status<0)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+ if (data->audio_fd<0)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ device->DeviceName=strdup(deviceName);
+ device->ExtraData=data;
+
+ return ALC_NO_ERROR;
+}
+
+static void qsa_close_playback(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+
+ if (data->buffer!=NULL)
+ {
+ free(data->buffer);
+ data->buffer=NULL;
+ }
+
+ snd_pcm_close(data->pcmHandle);
+ free(data);
+
+ device->ExtraData=NULL;
+}
+
+static ALCboolean qsa_reset_playback(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+ int32_t format=-1;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ format=SND_PCM_SFMT_S8;
+ break;
+ case DevFmtUByte:
+ format=SND_PCM_SFMT_U8;
+ break;
+ case DevFmtShort:
+ format=SND_PCM_SFMT_S16_LE;
+ break;
+ case DevFmtUShort:
+ format=SND_PCM_SFMT_U16_LE;
+ break;
+ case DevFmtInt:
+ format=SND_PCM_SFMT_S32_LE;
+ break;
+ case DevFmtUInt:
+ format=SND_PCM_SFMT_U32_LE;
+ break;
+ case DevFmtFloat:
+ format=SND_PCM_SFMT_FLOAT_LE;
+ break;
+ }
+
+ /* we actually don't want to block on writes */
+ snd_pcm_nonblock_mode(data->pcmHandle, 1);
+ /* Disable mmap to control data transfer to the audio device */
+ snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
+ snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS);
+
+ // configure a sound channel
+ memset(&data->cparams, 0, sizeof(data->cparams));
+ data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK;
+ data->cparams.mode=SND_PCM_MODE_BLOCK;
+ data->cparams.start_mode=SND_PCM_START_FULL;
+ data->cparams.stop_mode=SND_PCM_STOP_STOP;
+
+ data->cparams.buf.block.frag_size=device->UpdateSize*
+ ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+ data->cparams.buf.block.frags_max=device->NumUpdates;
+ data->cparams.buf.block.frags_min=device->NumUpdates;
+
+ data->cparams.format.interleave=1;
+ data->cparams.format.rate=device->Frequency;
+ data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+ data->cparams.format.format=format;
+
+ if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
+ {
+ int original_rate=data->cparams.format.rate;
+ int original_voices=data->cparams.format.voices;
+ int original_format=data->cparams.format.format;
+ int it;
+ int jt;
+
+ for (it=0; it<1; it++)
+ {
+ /* Check for second pass */
+ if (it==1)
+ {
+ original_rate=ratelist[0].rate;
+ original_voices=channellist[0].channels;
+ original_format=formatlist[0].format;
+ }
+
+ do {
+ /* At first downgrade sample format */
+ jt=0;
+ do {
+ if (formatlist[jt].format==data->cparams.format.format)
+ {
+ data->cparams.format.format=formatlist[jt+1].format;
+ break;
+ }
+ if (formatlist[jt].format==0)
+ {
+ data->cparams.format.format=0;
+ break;
+ }
+ jt++;
+ } while(1);
+
+ if (data->cparams.format.format==0)
+ {
+ data->cparams.format.format=original_format;
+
+ /* At secod downgrade sample rate */
+ jt=0;
+ do {
+ if (ratelist[jt].rate==data->cparams.format.rate)
+ {
+ data->cparams.format.rate=ratelist[jt+1].rate;
+ break;
+ }
+ if (ratelist[jt].rate==0)
+ {
+ data->cparams.format.rate=0;
+ break;
+ }
+ jt++;
+ } while(1);
+
+ if (data->cparams.format.rate==0)
+ {
+ data->cparams.format.rate=original_rate;
+ data->cparams.format.format=original_format;
+
+ /* At third downgrade channels number */
+ jt=0;
+ do {
+ if(channellist[jt].channels==data->cparams.format.voices)
+ {
+ data->cparams.format.voices=channellist[jt+1].channels;
+ break;
+ }
+ if (channellist[jt].channels==0)
+ {
+ data->cparams.format.voices=0;
+ break;
+ }
+ jt++;
+ } while(1);
+ }
+
+ if (data->cparams.format.voices==0)
+ {
+ break;
+ }
+ }
+
+ data->cparams.buf.block.frag_size=device->UpdateSize*
+ data->cparams.format.voices*
+ snd_pcm_format_width(data->cparams.format.format)/8;
+ data->cparams.buf.block.frags_max=device->NumUpdates;
+ data->cparams.buf.block.frags_min=device->NumUpdates;
+ if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ } while(1);
+
+ if (data->cparams.format.voices!=0)
+ {
+ break;
+ }
+ }
+
+ if (data->cparams.format.voices==0)
+ {
+ return ALC_FALSE;
+ }
+ }
+
+ if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
+ {
+ return ALC_FALSE;
+ }
+
+ memset(&data->csetup, 0, sizeof(data->csetup));
+ data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK;
+ if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0)
+ {
+ return ALC_FALSE;
+ }
+
+ /* now fill back to the our AL device */
+ device->Frequency=data->cparams.format.rate;
+
+ switch (data->cparams.format.voices)
+ {
+ case 1:
+ device->FmtChans=DevFmtMono;
+ break;
+ case 2:
+ device->FmtChans=DevFmtStereo;
+ break;
+ case 4:
+ device->FmtChans=DevFmtQuad;
+ break;
+ case 6:
+ device->FmtChans=DevFmtX51;
+ break;
+ case 7:
+ device->FmtChans=DevFmtX61;
+ break;
+ case 8:
+ device->FmtChans=DevFmtX71;
+ break;
+ default:
+ device->FmtChans=DevFmtMono;
+ break;
+ }
+
+ switch (data->cparams.format.format)
+ {
+ case SND_PCM_SFMT_S8:
+ device->FmtType=DevFmtByte;
+ break;
+ case SND_PCM_SFMT_U8:
+ device->FmtType=DevFmtUByte;
+ break;
+ case SND_PCM_SFMT_S16_LE:
+ device->FmtType=DevFmtShort;
+ break;
+ case SND_PCM_SFMT_U16_LE:
+ device->FmtType=DevFmtUShort;
+ break;
+ case SND_PCM_SFMT_S32_LE:
+ device->FmtType=DevFmtInt;
+ break;
+ case SND_PCM_SFMT_U32_LE:
+ device->FmtType=DevFmtUInt;
+ break;
+ case SND_PCM_SFMT_FLOAT_LE:
+ device->FmtType=DevFmtFloat;
+ break;
+ default:
+ device->FmtType=DevFmtShort;
+ break;
+ }
+
+ SetDefaultChannelOrder(device);
+
+ device->UpdateSize=data->csetup.buf.block.frag_size/
+ (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
+ device->NumUpdates=data->csetup.buf.block.frags;
+
+ data->size=data->csetup.buf.block.frag_size;
+ data->buffer=malloc(data->size);
+ if (!data->buffer)
+ {
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static ALCboolean qsa_start_playback(ALCdevice* device)
+{
+ qsa_data *data = (qsa_data*)device->ExtraData;
+
+ if(!StartThread(&data->thread, qsa_proc_playback, device))
+ return ALC_FALSE;
+
+ return ALC_TRUE;
+}
+
+static void qsa_stop_playback(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+
+ if (data->thread)
+ {
+ data->killNow=1;
+ StopThread(data->thread);
+ data->thread=NULL;
+ }
+ data->killNow=0;
+}
+
+/***********/
+/* Capture */
+/***********/
+
+static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
+{
+ qsa_data* data;
+ int format=-1;
+ char driver[64];
+ int card, dev;
+ int status;
+
+ strncpy(driver, GetConfigValue("qsa", "capture", qsaDevice), sizeof(driver)-1);
+ driver[sizeof(driver)-1]=0;
+
+ data=(qsa_data*)calloc(1, sizeof(qsa_data));
+ if (data==NULL)
+ {
+ return ALC_OUT_OF_MEMORY;
+ }
+
+ if (!deviceName)
+ {
+ deviceName=driver;
+ }
+
+ if (strcmp(deviceName, qsaDevice)==0)
+ {
+ if (!deviceName)
+ {
+ deviceName=qsaDevice;
+ }
+
+ status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
+ }
+ else
+ {
+ size_t idx;
+
+ if (!allCaptureDevNameMap)
+ {
+ allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numDevNames);
+ }
+
+ for (idx=0; idx<numDevNames; idx++)
+ {
+ if (allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name)==0)
+ {
+ if (idx>0)
+ {
+ break;
+ }
+ }
+ }
+ if (idx==numDevNames)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ status=snd_pcm_open(&data->pcmHandle, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev, SND_PCM_OPEN_CAPTURE);
+ }
+
+ if (status<0)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
+ if (data->audio_fd<0)
+ {
+ free(data);
+ return ALC_INVALID_DEVICE;
+ }
+
+ device->DeviceName=strdup(deviceName);
+ device->ExtraData=data;
+
+ switch (device->FmtType)
+ {
+ case DevFmtByte:
+ format=SND_PCM_SFMT_S8;
+ break;
+ case DevFmtUByte:
+ format=SND_PCM_SFMT_U8;
+ break;
+ case DevFmtShort:
+ format=SND_PCM_SFMT_S16_LE;
+ break;
+ case DevFmtUShort:
+ format=SND_PCM_SFMT_U16_LE;
+ break;
+ case DevFmtInt:
+ format=SND_PCM_SFMT_S32_LE;
+ break;
+ case DevFmtUInt:
+ format=SND_PCM_SFMT_U32_LE;
+ break;
+ case DevFmtFloat:
+ format=SND_PCM_SFMT_FLOAT_LE;
+ break;
+ }
+
+ /* we actually don't want to block on reads */
+ snd_pcm_nonblock_mode(data->pcmHandle, 1);
+ /* Disable mmap to control data transfer to the audio device */
+ snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
+
+ /* configure a sound channel */
+ memset(&data->cparams, 0, sizeof(data->cparams));
+ data->cparams.mode=SND_PCM_MODE_BLOCK;
+ data->cparams.channel=SND_PCM_CHANNEL_CAPTURE;
+ data->cparams.start_mode=SND_PCM_START_GO;
+ data->cparams.stop_mode=SND_PCM_STOP_STOP;
+
+ data->cparams.buf.block.frag_size=device->UpdateSize*
+ ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+ data->cparams.buf.block.frags_max=device->NumUpdates;
+ data->cparams.buf.block.frags_min=device->NumUpdates;
+
+ data->cparams.format.interleave=1;
+ data->cparams.format.rate=device->Frequency;
+ data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+ data->cparams.format.format=format;
+
+ if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
+ {
+ int original_rate=data->cparams.format.rate;
+ int original_voices=data->cparams.format.voices;
+ int original_format=data->cparams.format.format;
+ int it;
+ int jt;
+
+ for (it=0; it<1; it++)
+ {
+ /* Check for second pass */
+ if (it==1)
+ {
+ original_rate=ratelist[0].rate;
+ original_voices=channellist[0].channels;
+ original_format=formatlist[0].format;
+ }
+
+ do {
+ /* At first downgrade sample format */
+ jt=0;
+ do {
+ if (formatlist[jt].format==data->cparams.format.format)
+ {
+ data->cparams.format.format=formatlist[jt+1].format;
+ break;
+ }
+ if (formatlist[jt].format==0)
+ {
+ data->cparams.format.format=0;
+ break;
+ }
+ jt++;
+ } while(1);
+
+ if (data->cparams.format.format==0)
+ {
+ data->cparams.format.format=original_format;
+
+ /* At secod downgrade sample rate */
+ jt=0;
+ do {
+ if (ratelist[jt].rate==data->cparams.format.rate)
+ {
+ data->cparams.format.rate=ratelist[jt+1].rate;
+ break;
+ }
+ if (ratelist[jt].rate==0)
+ {
+ data->cparams.format.rate=0;
+ break;
+ }
+ jt++;
+ } while(1);
+
+ if (data->cparams.format.rate==0)
+ {
+ data->cparams.format.rate=original_rate;
+ data->cparams.format.format=original_format;
+
+ /* At third downgrade channels number */
+ jt=0;
+ do {
+ if(channellist[jt].channels==data->cparams.format.voices)
+ {
+ data->cparams.format.voices=channellist[jt+1].channels;
+ break;
+ }
+ if (channellist[jt].channels==0)
+ {
+ data->cparams.format.voices=0;
+ break;
+ }
+ jt++;
+ } while(1);
+ }
+
+ if (data->cparams.format.voices==0)
+ {
+ break;
+ }
+ }
+
+ data->cparams.buf.block.frag_size=device->UpdateSize*
+ data->cparams.format.voices*
+ snd_pcm_format_width(data->cparams.format.format)/8;
+ data->cparams.buf.block.frags_max=device->NumUpdates;
+ data->cparams.buf.block.frags_min=device->NumUpdates;
+ if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ } while(1);
+
+ if (data->cparams.format.voices!=0)
+ {
+ break;
+ }
+ }
+
+ if (data->cparams.format.voices==0)
+ {
+ return ALC_INVALID_VALUE;
+ }
+ }
+
+ /* now fill back to the our AL device */
+ device->Frequency=data->cparams.format.rate;
+
+ switch (data->cparams.format.voices)
+ {
+ case 1:
+ device->FmtChans=DevFmtMono;
+ break;
+ case 2:
+ device->FmtChans=DevFmtStereo;
+ break;
+ case 4:
+ device->FmtChans=DevFmtQuad;
+ break;
+ case 6:
+ device->FmtChans=DevFmtX51;
+ break;
+ case 7:
+ device->FmtChans=DevFmtX61;
+ break;
+ case 8:
+ device->FmtChans=DevFmtX71;
+ break;
+ default:
+ device->FmtChans=DevFmtMono;
+ break;
+ }
+
+ switch (data->cparams.format.format)
+ {
+ case SND_PCM_SFMT_S8:
+ device->FmtType=DevFmtByte;
+ break;
+ case SND_PCM_SFMT_U8:
+ device->FmtType=DevFmtUByte;
+ break;
+ case SND_PCM_SFMT_S16_LE:
+ device->FmtType=DevFmtShort;
+ break;
+ case SND_PCM_SFMT_U16_LE:
+ device->FmtType=DevFmtUShort;
+ break;
+ case SND_PCM_SFMT_S32_LE:
+ device->FmtType=DevFmtInt;
+ break;
+ case SND_PCM_SFMT_U32_LE:
+ device->FmtType=DevFmtUInt;
+ break;
+ case SND_PCM_SFMT_FLOAT_LE:
+ device->FmtType=DevFmtFloat;
+ break;
+ default:
+ device->FmtType=DevFmtShort;
+ break;
+ }
+
+ return ALC_NO_ERROR;
+}
+
+static void qsa_close_capture(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+
+ if (data->pcmHandle!=NULL)
+ {
+ snd_pcm_close(data->pcmHandle);
+ }
+ free(data);
+ device->ExtraData=NULL;
+}
+
+static void qsa_start_capture(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+ int rstatus;
+
+ if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
+ {
+ ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
+ return;
+ }
+
+ memset(&data->csetup, 0, sizeof(data->csetup));
+ data->csetup.channel=SND_PCM_CHANNEL_CAPTURE;
+ if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0)
+ {
+ ERR("capture setup failed: %s\n", snd_strerror(rstatus));
+ return;
+ }
+
+ snd_pcm_capture_go(data->pcmHandle);
+
+ device->UpdateSize=data->csetup.buf.block.frag_size/
+ (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
+ device->NumUpdates=data->csetup.buf.block.frags;
+}
+
+static void qsa_stop_capture(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+
+ snd_pcm_capture_flush(data->pcmHandle);
+}
+
+static ALCuint qsa_available_samples(ALCdevice* device)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+ snd_pcm_channel_status_t status;
+ ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ ALint free_size;
+ int rstatus;
+
+ memset(&status, 0, sizeof (status));
+ status.channel=SND_PCM_CHANNEL_CAPTURE;
+ snd_pcm_plugin_status(data->pcmHandle, &status);
+ if ((status.status==SND_PCM_STATUS_OVERRUN) ||
+ (status.status==SND_PCM_STATUS_READY))
+ {
+ if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
+ {
+ ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
+ aluHandleDisconnect(device);
+ return 0;
+ }
+
+ snd_pcm_capture_go(data->pcmHandle);
+ return 0;
+ }
+
+ free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags;
+ free_size-=status.free;
+
+ return free_size/frame_size;
+}
+
+static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+{
+ qsa_data* data=(qsa_data*)device->ExtraData;
+ char* read_ptr;
+ snd_pcm_channel_status_t status;
+ fd_set rfds;
+ int selectret;
+ struct timeval timeout;
+ int bytes_read;
+ ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ ALint len=samples*frame_size;
+ int rstatus;
+
+ read_ptr=buffer;
+
+ while (len>0)
+ {
+ FD_ZERO(&rfds);
+ FD_SET(data->audio_fd, &rfds);
+ timeout.tv_sec=2;
+ timeout.tv_usec=0;
+
+ /* Select also works like time slice to OS */
+ bytes_read=0;
+ selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout);
+ switch (selectret)
+ {
+ case -1:
+ aluHandleDisconnect(device);
+ return ALC_INVALID_DEVICE;
+ case 0:
+ break;
+ default:
+ if (FD_ISSET(data->audio_fd, &rfds))
+ {
+ bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len);
+ break;
+ }
+ break;
+ }
+
+ if (bytes_read<=0)
+ {
+ if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
+ {
+ continue;
+ }
+
+ memset(&status, 0, sizeof (status));
+ status.channel=SND_PCM_CHANNEL_CAPTURE;
+ snd_pcm_plugin_status(data->pcmHandle, &status);
+
+ /* we need to reinitialize the sound channel if we've overrun the buffer */
+ if ((status.status==SND_PCM_STATUS_OVERRUN) ||
+ (status.status==SND_PCM_STATUS_READY))
+ {
+ if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
+ {
+ ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
+ aluHandleDisconnect(device);
+ return ALC_INVALID_DEVICE;
+ }
+ snd_pcm_capture_go(data->pcmHandle);
+ }
+ }
+ else
+ {
+ read_ptr+=bytes_read;
+ len-=bytes_read;
+ }
+ }
+
+ return ALC_NO_ERROR;
+}
+
+static ALint64 qsa_get_latency(ALCdevice* device)
+{
+ ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+ return (ALint64)(device->UpdateSize*device->NumUpdates/frame_size)*
+ 1000000000/device->Frequency;
+}
+
+BackendFuncs qsa_funcs=
+{
+ qsa_open_playback,
+ qsa_close_playback,
+ qsa_reset_playback,
+ qsa_start_playback,
+ qsa_stop_playback,
+ qsa_open_capture,
+ qsa_close_capture,
+ qsa_start_capture,
+ qsa_stop_capture,
+ qsa_capture_samples,
+ qsa_available_samples,
+ qsa_get_latency,
+};
+
+ALCboolean alc_qsa_init(BackendFuncs* func_list)
+{
+ *func_list=qsa_funcs;
+
+ return ALC_TRUE;
+}
+
+void alc_qsa_deinit(void)
+{
+ ALuint i;
+
+ for (i=0; i<numDevNames; ++i)
+ {
+ free(allDevNameMap[i].name);
+ }
+ free(allDevNameMap);
+ allDevNameMap=NULL;
+ numDevNames=0;
+
+ for (i=0; i<numCaptureDevNames; ++i)
+ {
+ free(allCaptureDevNameMap[i].name);
+ }
+ free(allCaptureDevNameMap);
+ allCaptureDevNameMap=NULL;
+ numCaptureDevNames=0;
+}
+
+void alc_qsa_probe(enum DevProbe type)
+{
+ ALuint i;
+
+ switch (type)
+ {
+ case ALL_DEVICE_PROBE:
+ for (i=0; i<numDevNames; ++i)
+ {
+ free(allDevNameMap[i].name);
+ }
+ free(allDevNameMap);
+
+ allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
+ for (i=0; i<numDevNames; ++i)
+ {
+ AppendAllDevicesList(allDevNameMap[i].name);
+ }
+ break;
+ case CAPTURE_DEVICE_PROBE:
+ for (i=0; i<numCaptureDevNames; ++i)
+ {
+ free(allCaptureDevNameMap[i].name);
+ }
+ free(allCaptureDevNameMap);
+
+ allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numCaptureDevNames);
+ for (i=0; i<numCaptureDevNames; ++i)
+ {
+ AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+ }
+ break;
+ }
+}
diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c
index 2be88746..80aebfd1 100644
--- a/Alc/backends/sndio.c
+++ b/Alc/backends/sndio.c
@@ -26,6 +26,7 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
#include <sndio.h>
@@ -46,7 +47,7 @@ typedef struct {
ALsizei data_size;
volatile int killNow;
- ALvoid *thread;
+ althread_t thread;
} sndio_data;
@@ -58,6 +59,7 @@ static ALuint sndio_proc(ALvoid *ptr)
size_t wrote;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -222,8 +224,7 @@ static ALCboolean sndio_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
- data->thread = StartThread(sndio_proc, device);
- if(data->thread == NULL)
+ if(!StartThread(&data->thread, sndio_proc, device))
{
sio_stop(data->sndHandle);
free(data->mix_data);
@@ -266,8 +267,6 @@ static const BackendFuncs sndio_funcs = {
NULL,
NULL,
NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c
index 1c781387..700131c8 100644
--- a/Alc/backends/solaris.c
+++ b/Alc/backends/solaris.c
@@ -33,6 +33,8 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
#include <sys/audioio.h>
@@ -43,11 +45,12 @@ static const char *solaris_driver = "/dev/audio";
typedef struct {
int fd;
- volatile int killNow;
- ALvoid *thread;
ALubyte *mix_data;
int data_size;
+
+ volatile int killNow;
+ althread_t thread;
} solaris_data;
@@ -59,6 +62,7 @@ static ALuint SolarisProc(ALvoid *ptr)
int wrote;
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
@@ -207,8 +211,7 @@ static ALCboolean solaris_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
- data->thread = StartThread(SolarisProc, device);
- if(data->thread == NULL)
+ if(!StartThread(&data->thread, SolarisProc, device))
{
free(data->mix_data);
data->mix_data = NULL;
@@ -250,8 +253,6 @@ static const BackendFuncs solaris_funcs = {
NULL,
NULL,
NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c
index be528c9a..2fafc4b9 100644
--- a/Alc/backends/wave.c
+++ b/Alc/backends/wave.c
@@ -23,12 +23,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
+#include <errno.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
+#include "compat.h"
typedef struct {
@@ -39,7 +42,7 @@ typedef struct {
ALuint size;
volatile int killNow;
- ALvoid *thread;
+ althread_t thread;
} wave_data;
@@ -93,6 +96,8 @@ static ALuint WaveProc(ALvoid *ptr)
const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
Device->Frequency / 2;
+ SetThreadName(MIXER_THREAD_NAME);
+
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
done = 0;
@@ -146,7 +151,7 @@ static ALuint WaveProc(ALvoid *ptr)
{
fs = fwrite(data->buffer, frameSize, Device->UpdateSize,
data->f);
- fs = fs;
+ (void)fs;
}
if(ferror(data->f))
{
@@ -257,7 +262,7 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
fwrite32le(channel_masks[channels], data->f);
// 16 byte GUID, sub-type format
val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
- val = val;
+ (void)val;
fprintf(data->f, "data");
fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
@@ -286,8 +291,7 @@ static ALCboolean wave_start_playback(ALCdevice *device)
return ALC_FALSE;
}
- data->thread = StartThread(WaveProc, device);
- if(data->thread == NULL)
+ if(!StartThread(&data->thread, WaveProc, device))
{
free(data->buffer);
data->buffer = NULL;
@@ -339,8 +343,6 @@ static const BackendFuncs wave_funcs = {
NULL,
NULL,
NULL,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c
index 4786d9b4..7082a874 100644
--- a/Alc/backends/winmm.c
+++ b/Alc/backends/winmm.c
@@ -29,6 +29,7 @@
#include "alMain.h"
#include "alu.h"
+#include "threads.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
@@ -146,14 +147,11 @@ static void ProbeCaptureDevices(void)
Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
returns to the application (for more data)
*/
-static void CALLBACK WaveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2)
+static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
{
ALCdevice *Device = (ALCdevice*)instance;
WinMMData *data = Device->ExtraData;
- (void)device;
- (void)param2;
-
if(msg != WOM_DONE)
return;
@@ -167,7 +165,7 @@ static void CALLBACK WaveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance,
Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
audio data.
*/
-static DWORD WINAPI PlaybackThreadProc(LPVOID param)
+FORCE_ALIGN static DWORD WINAPI PlaybackThreadProc(LPVOID param)
{
ALCdevice *Device = (ALCdevice*)param;
WinMMData *data = Device->ExtraData;
@@ -178,6 +176,7 @@ static DWORD WINAPI PlaybackThreadProc(LPVOID param)
FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
SetRTPriority();
+ SetThreadName(MIXER_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -213,14 +212,11 @@ static DWORD WINAPI PlaybackThreadProc(LPVOID param)
Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
returns to the application (with more data)
*/
-static void CALLBACK WaveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2)
+static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
{
ALCdevice *Device = (ALCdevice*)instance;
WinMMData *data = Device->ExtraData;
- (void)device;
- (void)param2;
-
if(msg != WIM_DATA)
return;
@@ -243,6 +239,7 @@ static DWORD WINAPI CaptureThreadProc(LPVOID param)
MSG msg;
FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
+ SetThreadName("alsoft-record");
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -716,8 +713,6 @@ static const BackendFuncs WinMMFuncs = {
WinMMStopCapture,
WinMMCaptureSamples,
WinMMAvailableSamples,
- ALCdevice_LockDefault,
- ALCdevice_UnlockDefault,
ALCdevice_GetLatencyDefault
};
diff --git a/Alc/compat.h b/Alc/compat.h
new file mode 100644
index 00000000..dbbcce28
--- /dev/null
+++ b/Alc/compat.h
@@ -0,0 +1,65 @@
+#ifndef AL_COMPAT_H
+#define AL_COMPAT_H
+
+#include "AL/al.h"
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef DWORD althread_key_t;
+int althread_key_create(althread_key_t *key, void (*callback)(void*));
+int althread_key_delete(althread_key_t key);
+void *althread_getspecific(althread_key_t key);
+int althread_setspecific(althread_key_t key, void *val);
+
+typedef LONG althread_once_t;
+#define ALTHREAD_ONCE_INIT 0
+void althread_once(althread_once_t *once, void (*callback)(void));
+
+inline int alsched_yield(void)
+{ SwitchToThread(); return 0; }
+
+WCHAR *strdupW(const WCHAR *str);
+
+#define HAVE_DYNLOAD 1
+
+#else
+
+#include <pthread.h>
+
+typedef pthread_mutex_t CRITICAL_SECTION;
+void InitializeCriticalSection(CRITICAL_SECTION *cs);
+void DeleteCriticalSection(CRITICAL_SECTION *cs);
+void EnterCriticalSection(CRITICAL_SECTION *cs);
+void LeaveCriticalSection(CRITICAL_SECTION *cs);
+
+ALuint timeGetTime(void);
+void Sleep(ALuint t);
+
+#define althread_key_t pthread_key_t
+#define althread_key_create pthread_key_create
+#define althread_key_delete pthread_key_delete
+#define althread_getspecific pthread_getspecific
+#define althread_setspecific pthread_setspecific
+
+#define althread_once_t pthread_once_t
+#define ALTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
+#define althread_once pthread_once
+
+#define alsched_yield sched_yield
+
+#if defined(HAVE_DLFCN_H)
+#define HAVE_DYNLOAD 1
+#endif
+
+#endif
+
+#ifdef HAVE_DYNLOAD
+void *LoadLib(const char *name);
+void CloseLib(void *handle);
+void *GetSymbol(void *handle, const char *name);
+#endif
+
+#endif /* AL_COMPAT_H */
diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c
new file mode 100644
index 00000000..9a45e233
--- /dev/null
+++ b/Alc/effects/autowah.c
@@ -0,0 +1,275 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Anis A. Hireche, Nasca Octavian Paul
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "alu.h"
+#include "alFilter.h"
+#include "alError.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+
+
+/* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up
+ * or down depending on the input signal, and a resonant peak at the cutoff.
+ *
+ * Currently, we assume a cutoff frequency range of 500hz (no amplitude) to
+ * 3khz (peak gain). Peak gain is assumed to be in normalized scale.
+ */
+
+typedef struct ALautowahState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ /* Effect gains for each channel */
+ ALfloat Gain[MaxChannels];
+
+ /* Effect parameters */
+ ALfloat AttackRate;
+ ALfloat ReleaseRate;
+ ALfloat Resonance;
+ ALfloat PeakGain;
+ ALfloat GainCtrl;
+ ALfloat Frequency;
+
+ /* Samples processing */
+ ALfilterState LowPass;
+} ALautowahState;
+
+static ALvoid ALautowahState_Destruct(ALautowahState *UNUSED(state))
+{
+}
+
+static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device)
+{
+ state->Frequency = device->Frequency;
+ return AL_TRUE;
+}
+
+static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot)
+{
+ ALfloat attackTime, releaseTime;
+ ALfloat gain;
+
+ attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
+ releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
+
+ state->AttackRate = 1.0f / attackTime;
+ state->ReleaseRate = 1.0f / releaseTime;
+ state->PeakGain = slot->EffectProps.Autowah.PeakGain;
+ state->Resonance = slot->EffectProps.Autowah.Resonance;
+
+ gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
+ SetGains(device, gain, state->Gain);
+}
+
+static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+{
+ ALuint it, kt;
+ ALuint base;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64];
+ ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat gain = state->GainCtrl;
+
+ for(it = 0;it < td;it++)
+ {
+ ALfloat smp = SamplesIn[it+base];
+ ALfloat alpha, w0;
+ ALfloat amplitude;
+ ALfloat cutoff;
+
+ /* Similar to compressor, we get the current amplitude of the
+ * incoming signal, and attack or release to reach it. */
+ amplitude = fabs(smp);
+ if(amplitude > gain)
+ gain = minf(gain+state->AttackRate, amplitude);
+ else if(amplitude < gain)
+ gain = maxf(gain-state->ReleaseRate, amplitude);
+ gain = maxf(gain, GAIN_SILENCE_THRESHOLD);
+
+ /* FIXME: What range does the filter cover? */
+ cutoff = lerp(1000.0f, (ALfloat)LOWPASSFREQREF, minf(gain/state->PeakGain, 1.0f));
+
+ /* The code below is like calling ALfilterState_setParams with
+ * ALfilterType_LowPass. However, instead of passing a bandwidth,
+ * we use the resonance property for Q. This also inlines the call.
+ */
+ w0 = F_2PI * cutoff / state->Frequency;
+
+ /* FIXME: Resonance controls the resonant peak, or Q. How? Not sure
+ * that Q = resonance*0.1. */
+ alpha = sinf(w0) / (2.0f * state->Resonance*0.1f);
+ state->LowPass.b[0] = (1.0f - cosf(w0)) / 2.0f;
+ state->LowPass.b[1] = 1.0f - cosf(w0);
+ state->LowPass.b[2] = (1.0f - cosf(w0)) / 2.0f;
+ state->LowPass.a[0] = 1.0f + alpha;
+ state->LowPass.a[1] = -2.0f * cosf(w0);
+ state->LowPass.a[2] = 1.0f - alpha;
+
+ state->LowPass.b[2] /= state->LowPass.a[0];
+ state->LowPass.b[1] /= state->LowPass.a[0];
+ state->LowPass.b[0] /= state->LowPass.a[0];
+ state->LowPass.a[2] /= state->LowPass.a[0];
+ state->LowPass.a[1] /= state->LowPass.a[0];
+ state->LowPass.a[0] /= state->LowPass.a[0];
+
+ temps[it] = ALfilterState_processSingle(&state->LowPass, smp);
+ }
+ state->GainCtrl = gain;
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[kt];
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][base+it] += gain * temps[it];
+ }
+
+ base += td;
+ }
+}
+
+static void ALautowahState_Delete(ALautowahState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState);
+
+
+typedef struct ALautowahStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALautowahStateFactory;
+
+static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *UNUSED(factory))
+{
+ ALautowahState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALautowahState, ALeffectState, state);
+
+ state->AttackRate = 0.0f;
+ state->ReleaseRate = 0.0f;
+ state->Resonance = 0.0f;
+ state->PeakGain = 1.0f;
+ state->GainCtrl = 1.0f;
+
+ ALfilterState_clear(&state->LowPass);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALautowahStateFactory);
+
+ALeffectStateFactory *ALautowahStateFactory_getFactory(void)
+{
+ static ALautowahStateFactory AutowahFactory = { { GET_VTABLE2(ALautowahStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &AutowahFactory);
+}
+
+
+void ALautowah_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALautowah_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALautowah_setParami(effect, context, param, vals[0]);
+}
+void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_AUTOWAH_ATTACK_TIME:
+ if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Autowah.AttackTime = val;
+ break;
+
+ case AL_AUTOWAH_RELEASE_TIME:
+ if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Autowah.ReleaseTime = val;
+ break;
+
+ case AL_AUTOWAH_RESONANCE:
+ if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Autowah.Resonance = val;
+ break;
+
+ case AL_AUTOWAH_PEAK_GAIN:
+ if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Autowah.PeakGain = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALautowah_setParamf(effect, context, param, vals[0]);
+}
+
+void ALautowah_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALautowah_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALautowah_getParami(effect, context, param, vals);
+}
+void ALautowah_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_AUTOWAH_ATTACK_TIME:
+ *val = props->Autowah.AttackTime;
+ break;
+
+ case AL_AUTOWAH_RELEASE_TIME:
+ *val = props->Autowah.ReleaseTime;
+ break;
+
+ case AL_AUTOWAH_RESONANCE:
+ *val = props->Autowah.Resonance;
+ break;
+
+ case AL_AUTOWAH_PEAK_GAIN:
+ *val = props->Autowah.PeakGain;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALautowah_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALautowah_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALautowah);
diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c
new file mode 100644
index 00000000..4945faf2
--- /dev/null
+++ b/Alc/effects/chorus.c
@@ -0,0 +1,381 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Mike Gorchak
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALchorusState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ ALfloat *SampleBuffer[2];
+ ALuint BufferLength;
+ ALuint offset;
+ ALuint lfo_range;
+ ALfloat lfo_scale;
+ ALint lfo_disp;
+
+ /* Gains for left and right sides */
+ ALfloat Gain[2][MaxChannels];
+
+ /* effect parameters */
+ ALint waveform;
+ ALint delay;
+ ALfloat depth;
+ ALfloat feedback;
+} ALchorusState;
+
+static ALvoid ALchorusState_Destruct(ALchorusState *state)
+{
+ free(state->SampleBuffer[0]);
+ state->SampleBuffer[0] = NULL;
+ state->SampleBuffer[1] = NULL;
+}
+
+static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
+{
+ ALuint maxlen;
+ ALuint it;
+
+ maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1;
+ maxlen = NextPowerOf2(maxlen);
+
+ if(maxlen != state->BufferLength)
+ {
+ void *temp;
+
+ temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2);
+ if(!temp) return AL_FALSE;
+ state->SampleBuffer[0] = temp;
+ state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
+
+ state->BufferLength = maxlen;
+ }
+
+ for(it = 0;it < state->BufferLength;it++)
+ {
+ state->SampleBuffer[0][it] = 0.0f;
+ state->SampleBuffer[1][it] = 0.0f;
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALfloat frequency = (ALfloat)Device->Frequency;
+ ALfloat rate;
+ ALint phase;
+
+ state->waveform = Slot->EffectProps.Chorus.Waveform;
+ state->depth = Slot->EffectProps.Chorus.Depth;
+ state->feedback = Slot->EffectProps.Chorus.Feedback;
+ state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
+
+ /* Gains for left and right sides */
+ ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
+ ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+
+ phase = Slot->EffectProps.Chorus.Phase;
+ rate = Slot->EffectProps.Chorus.Rate;
+ if(!(rate > 0.0f))
+ {
+ state->lfo_scale = 0.0f;
+ state->lfo_range = 1;
+ state->lfo_disp = 0;
+ }
+ else
+ {
+ /* Calculate LFO coefficient */
+ state->lfo_range = fastf2u(frequency/rate + 0.5f);
+ switch(state->waveform)
+ {
+ case AL_CHORUS_WAVEFORM_TRIANGLE:
+ state->lfo_scale = 4.0f / state->lfo_range;
+ break;
+ case AL_CHORUS_WAVEFORM_SINUSOID:
+ state->lfo_scale = F_2PI / state->lfo_range;
+ break;
+ }
+
+ /* Calculate lfo phase displacement */
+ state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
+ }
+}
+
+static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+{
+ ALfloat lfo_value;
+
+ lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_left = fastf2i(lfo_value) + state->delay;
+
+ offset += state->lfo_disp;
+ lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_right = fastf2i(lfo_value) + state->delay;
+}
+
+static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+{
+ ALfloat lfo_value;
+
+ lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_left = fastf2i(lfo_value) + state->delay;
+
+ offset += state->lfo_disp;
+ lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_right = fastf2i(lfo_value) + state->delay;
+}
+
+#define DECL_TEMPLATE(Func) \
+static void Process##Func(ALchorusState *state, const ALuint SamplesToDo, \
+ const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
+{ \
+ const ALuint bufmask = state->BufferLength-1; \
+ ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
+ ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
+ ALuint offset = state->offset; \
+ const ALfloat feedback = state->feedback; \
+ ALuint it; \
+ \
+ for(it = 0;it < SamplesToDo;it++) \
+ { \
+ ALint delay_left, delay_right; \
+ Func(&delay_left, &delay_right, offset, state); \
+ \
+ out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
+ leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
+ \
+ out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
+ rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
+ \
+ offset++; \
+ } \
+ state->offset = offset; \
+}
+
+DECL_TEMPLATE(Triangle)
+DECL_TEMPLATE(Sinusoid)
+
+#undef DECL_TEMPLATE
+
+static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ ALuint it, kt;
+ ALuint base;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64][2];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ if(state->waveform == AL_CHORUS_WAVEFORM_TRIANGLE)
+ ProcessTriangle(state, td, SamplesIn+base, temps);
+ else if(state->waveform == AL_CHORUS_WAVEFORM_SINUSOID)
+ ProcessSinusoid(state, td, SamplesIn+base, temps);
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[0][kt];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][it+base] += temps[it][0] * gain;
+ }
+
+ gain = state->Gain[1][kt];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][it+base] += temps[it][1] * gain;
+ }
+ }
+
+ base += td;
+ }
+}
+
+static void ALchorusState_Delete(ALchorusState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
+
+
+typedef struct ALchorusStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALchorusStateFactory;
+
+static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory))
+{
+ ALchorusState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALchorusState, ALeffectState, state);
+
+ state->BufferLength = 0;
+ state->SampleBuffer[0] = NULL;
+ state->SampleBuffer[1] = NULL;
+ state->offset = 0;
+ state->lfo_range = 1;
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory);
+
+
+ALeffectStateFactory *ALchorusStateFactory_getFactory(void)
+{
+ static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &ChorusFactory);
+}
+
+
+void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_CHORUS_WAVEFORM:
+ if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Waveform = val;
+ break;
+
+ case AL_CHORUS_PHASE:
+ if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Phase = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALchorus_setParami(effect, context, param, vals[0]);
+}
+void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_CHORUS_RATE:
+ if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Rate = val;
+ break;
+
+ case AL_CHORUS_DEPTH:
+ if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Depth = val;
+ break;
+
+ case AL_CHORUS_FEEDBACK:
+ if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Feedback = val;
+ break;
+
+ case AL_CHORUS_DELAY:
+ if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Chorus.Delay = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALchorus_setParamf(effect, context, param, vals[0]);
+}
+
+void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_CHORUS_WAVEFORM:
+ *val = props->Chorus.Waveform;
+ break;
+
+ case AL_CHORUS_PHASE:
+ *val = props->Chorus.Phase;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALchorus_getParami(effect, context, param, vals);
+}
+void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_CHORUS_RATE:
+ *val = props->Chorus.Rate;
+ break;
+
+ case AL_CHORUS_DEPTH:
+ *val = props->Chorus.Depth;
+ break;
+
+ case AL_CHORUS_FEEDBACK:
+ *val = props->Chorus.Feedback;
+ break;
+
+ case AL_CHORUS_DELAY:
+ *val = props->Chorus.Delay;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALchorus_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALchorus);
diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c
new file mode 100644
index 00000000..14c0ed10
--- /dev/null
+++ b/Alc/effects/compressor.c
@@ -0,0 +1,223 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Anis A. Hireche
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "alError.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alu.h"
+
+
+typedef struct ALcompressorState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ /* Effect gains for each channel */
+ ALfloat Gain[MaxChannels];
+
+ /* Effect parameters */
+ ALboolean Enabled;
+ ALfloat AttackRate;
+ ALfloat ReleaseRate;
+ ALfloat GainCtrl;
+} ALcompressorState;
+
+static ALvoid ALcompressorState_Destruct(ALcompressorState *UNUSED(state))
+{
+}
+
+static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
+{
+ const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
+ const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
+
+ state->AttackRate = 1.0f / attackTime;
+ state->ReleaseRate = 1.0f / releaseTime;
+
+ return AL_TRUE;
+}
+
+static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALfloat gain;
+
+ state->Enabled = Slot->EffectProps.Compressor.OnOff;
+
+ gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
+ SetGains(Device, gain, state->Gain);
+}
+
+static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+{
+ ALuint it, kt;
+ ALuint base;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ if(state->Enabled)
+ {
+ ALfloat output, smp, amplitude;
+ ALfloat gain = state->GainCtrl;
+
+ for(it = 0;it < td;it++)
+ {
+ smp = SamplesIn[it+base];
+
+ amplitude = fabs(smp);
+ if(amplitude > gain)
+ gain = minf(gain+state->AttackRate, amplitude);
+ else if(amplitude < gain)
+ gain = maxf(gain-state->ReleaseRate, amplitude);
+ output = 1.0 / clampf(gain, 0.5f, 2.0f);
+
+ temps[it] = smp * output;
+ }
+
+ state->GainCtrl = gain;
+ }
+ else
+ {
+ ALfloat output, smp, amplitude;
+ ALfloat gain = state->GainCtrl;
+
+ for(it = 0;it < td;it++)
+ {
+ smp = SamplesIn[it+base];
+
+ amplitude = 1.0f;
+ if(amplitude > gain)
+ gain = minf(gain+state->AttackRate, amplitude);
+ else if(amplitude < gain)
+ gain = maxf(gain-state->ReleaseRate, amplitude);
+ output = 1.0f / clampf(gain, 0.5f, 2.0f);
+
+ temps[it] = smp * output;
+ }
+
+ state->GainCtrl = gain;
+ }
+
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[kt];
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][base+it] += gain * temps[it];
+ }
+
+ base += td;
+ }
+}
+
+static void ALcompressorState_Delete(ALcompressorState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
+
+
+typedef struct ALcompressorStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALcompressorStateFactory;
+
+static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
+{
+ ALcompressorState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALcompressorState, ALeffectState, state);
+
+ state->Enabled = AL_TRUE;
+ state->AttackRate = 0.0f;
+ state->ReleaseRate = 0.0f;
+ state->GainCtrl = 1.0f;
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
+
+ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
+{
+ static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
+}
+
+
+void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_COMPRESSOR_ONOFF:
+ if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Compressor.OnOff = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALcompressor_setParami(effect, context, param, vals[0]);
+}
+void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALcompressor_setParamf(effect, context, param, vals[0]);
+}
+
+void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_COMPRESSOR_ONOFF:
+ *val = props->Compressor.OnOff;
+ break;
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALcompressor_getParami(effect, context, param, vals);
+}
+void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALcompressor_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALcompressor);
diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c
new file mode 100644
index 00000000..fe57c7d8
--- /dev/null
+++ b/Alc/effects/dedicated.c
@@ -0,0 +1,167 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2011 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALdedicatedState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ ALfloat gains[MaxChannels];
+} ALdedicatedState;
+
+
+static ALvoid ALdedicatedState_Destruct(ALdedicatedState *UNUSED(state))
+{
+}
+
+static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
+{
+ return AL_TRUE;
+}
+
+static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot)
+{
+ ALfloat Gain;
+ ALsizei s;
+
+ Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
+ if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
+ ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains);
+ else if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+ {
+ for(s = 0;s < MaxChannels;s++)
+ state->gains[s] = 0.0f;
+ state->gains[LFE] = Gain;
+ }
+}
+
+static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ const ALfloat *gains = state->gains;
+ ALuint i, c;
+
+ for(c = 0;c < MaxChannels;c++)
+ {
+ if(!(gains[c] > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(i = 0;i < SamplesToDo;i++)
+ SamplesOut[c][i] = SamplesIn[i] * gains[c];
+ }
+}
+
+static void ALdedicatedState_Delete(ALdedicatedState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
+
+
+typedef struct ALdedicatedStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALdedicatedStateFactory;
+
+ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory))
+{
+ ALdedicatedState *state;
+ ALsizei s;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALdedicatedState, ALeffectState, state);
+
+ for(s = 0;s < MaxChannels;s++)
+ state->gains[s] = 0.0f;
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory);
+
+
+ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void)
+{
+ static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory);
+}
+
+
+void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALdedicated_setParami(effect, context, param, vals[0]);
+}
+void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_DEDICATED_GAIN:
+ if(!(val >= 0.0f && isfinite(val)))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Dedicated.Gain = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALdedicated_setParamf(effect, context, param, vals[0]);
+}
+
+void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALdedicated_getParami(effect, context, param, vals);
+}
+void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_DEDICATED_GAIN:
+ *val = props->Dedicated.Gain;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALdedicated_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALdedicated);
diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c
new file mode 100644
index 00000000..e39a8197
--- /dev/null
+++ b/Alc/effects/distortion.c
@@ -0,0 +1,300 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Mike Gorchak
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALdistortionState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ /* Effect gains for each channel */
+ ALfloat Gain[MaxChannels];
+
+ /* Effect parameters */
+ ALfilterState lowpass;
+ ALfilterState bandpass;
+ ALfloat attenuation;
+ ALfloat edge_coeff;
+} ALdistortionState;
+
+static ALvoid ALdistortionState_Destruct(ALdistortionState *UNUSED(state))
+{
+}
+
+static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
+{
+ return AL_TRUE;
+}
+
+static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALfloat frequency = (ALfloat)Device->Frequency;
+ ALfloat bandwidth;
+ ALfloat cutoff;
+ ALfloat edge;
+ ALfloat gain;
+
+ /* Store distorted signal attenuation settings */
+ state->attenuation = Slot->EffectProps.Distortion.Gain;
+
+ /* Store waveshaper edge settings */
+ edge = sinf(Slot->EffectProps.Distortion.Edge * (F_PI_2));
+ edge = minf(edge, 0.99f);
+ state->edge_coeff = 2.0f * edge / (1.0f-edge);
+
+ /* Lowpass filter */
+ cutoff = Slot->EffectProps.Distortion.LowpassCutoff;
+ /* Bandwidth value is constant in octaves */
+ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
+ ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
+ cutoff / (frequency*4.0f), bandwidth);
+
+ /* Bandpass filter */
+ cutoff = Slot->EffectProps.Distortion.EQCenter;
+ /* Convert bandwidth in Hz to octaves */
+ bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
+ ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
+ cutoff / (frequency*4.0f), bandwidth);
+
+ gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
+ SetGains(Device, gain, state->Gain);
+}
+
+static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ const ALfloat fc = state->edge_coeff;
+ float oversample_buffer[64][4];
+ ALuint base;
+ ALuint it;
+ ALuint ot;
+ ALuint kt;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ /* Perform 4x oversampling to avoid aliasing. */
+ /* Oversampling greatly improves distortion */
+ /* quality and allows to implement lowpass and */
+ /* bandpass filters using high frequencies, at */
+ /* which classic IIR filters became unstable. */
+
+ /* Fill oversample buffer using zero stuffing */
+ for(it = 0;it < td;it++)
+ {
+ oversample_buffer[it][0] = SamplesIn[it+base];
+ oversample_buffer[it][1] = 0.0f;
+ oversample_buffer[it][2] = 0.0f;
+ oversample_buffer[it][3] = 0.0f;
+ }
+
+ /* First step, do lowpass filtering of original signal, */
+ /* additionally perform buffer interpolation and lowpass */
+ /* cutoff for oversampling (which is fortunately first */
+ /* step of distortion). So combine three operations into */
+ /* the one. */
+ for(it = 0;it < td;it++)
+ {
+ for(ot = 0;ot < 4;ot++)
+ {
+ ALfloat smp;
+ smp = ALfilterState_processSingle(&state->lowpass, oversample_buffer[it][ot]);
+
+ /* Restore signal power by multiplying sample by amount of oversampling */
+ oversample_buffer[it][ot] = smp * 4.0f;
+ }
+ }
+
+ for(it = 0;it < td;it++)
+ {
+ /* Second step, do distortion using waveshaper function */
+ /* to emulate signal processing during tube overdriving. */
+ /* Three steps of waveshaping are intended to modify */
+ /* waveform without boost/clipping/attenuation process. */
+ for(ot = 0;ot < 4;ot++)
+ {
+ ALfloat smp = oversample_buffer[it][ot];
+
+ smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
+ smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
+ smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
+
+ /* Third step, do bandpass filtering of distorted signal */
+ smp = ALfilterState_processSingle(&state->bandpass, smp);
+ oversample_buffer[it][ot] = smp;
+ }
+
+ /* Fourth step, final, do attenuation and perform decimation, */
+ /* store only one sample out of 4. */
+ temps[it] = oversample_buffer[it][0] * state->attenuation;
+ }
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[kt];
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][base+it] += gain * temps[it];
+ }
+
+ base += td;
+ }
+}
+
+static void ALdistortionState_Delete(ALdistortionState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
+
+
+typedef struct ALdistortionStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALdistortionStateFactory;
+
+static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
+{
+ ALdistortionState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALdistortionState, ALeffectState, state);
+
+ ALfilterState_clear(&state->lowpass);
+ ALfilterState_clear(&state->bandpass);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
+
+
+ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
+{
+ static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
+}
+
+
+void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALdistortion_setParami(effect, context, param, vals[0]);
+}
+void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_DISTORTION_EDGE:
+ if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Distortion.Edge = val;
+ break;
+
+ case AL_DISTORTION_GAIN:
+ if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Distortion.Gain = val;
+ break;
+
+ case AL_DISTORTION_LOWPASS_CUTOFF:
+ if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Distortion.LowpassCutoff = val;
+ break;
+
+ case AL_DISTORTION_EQCENTER:
+ if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Distortion.EQCenter = val;
+ break;
+
+ case AL_DISTORTION_EQBANDWIDTH:
+ if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Distortion.EQBandwidth = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALdistortion_setParamf(effect, context, param, vals[0]);
+}
+
+void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALdistortion_getParami(effect, context, param, vals);
+}
+void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_DISTORTION_EDGE:
+ *val = props->Distortion.Edge;
+ break;
+
+ case AL_DISTORTION_GAIN:
+ *val = props->Distortion.Gain;
+ break;
+
+ case AL_DISTORTION_LOWPASS_CUTOFF:
+ *val = props->Distortion.LowpassCutoff;
+ break;
+
+ case AL_DISTORTION_EQCENTER:
+ *val = props->Distortion.EQCenter;
+ break;
+
+ case AL_DISTORTION_EQBANDWIDTH:
+ *val = props->Distortion.EQBandwidth;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALdistortion_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALdistortion);
diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c
new file mode 100644
index 00000000..7471c3dd
--- /dev/null
+++ b/Alc/effects/echo.c
@@ -0,0 +1,296 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALechoState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ ALfloat *SampleBuffer;
+ ALuint BufferLength;
+
+ // The echo is two tap. The delay is the number of samples from before the
+ // current offset
+ struct {
+ ALuint delay;
+ } Tap[2];
+ ALuint Offset;
+ /* The panning gains for the two taps */
+ ALfloat Gain[2][MaxChannels];
+
+ ALfloat FeedGain;
+
+ ALfilterState Filter;
+} ALechoState;
+
+static ALvoid ALechoState_Destruct(ALechoState *state)
+{
+ free(state->SampleBuffer);
+ state->SampleBuffer = NULL;
+}
+
+static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
+{
+ ALuint maxlen, i;
+
+ // Use the next power of 2 for the buffer length, so the tap offsets can be
+ // wrapped using a mask instead of a modulo
+ maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
+ maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
+ maxlen = NextPowerOf2(maxlen);
+
+ if(maxlen != state->BufferLength)
+ {
+ void *temp;
+
+ temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
+ if(!temp) return AL_FALSE;
+ state->SampleBuffer = temp;
+ state->BufferLength = maxlen;
+ }
+ for(i = 0;i < state->BufferLength;i++)
+ state->SampleBuffer[i] = 0.0f;
+
+ return AL_TRUE;
+}
+
+static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALuint frequency = Device->Frequency;
+ ALfloat lrpan, gain;
+ ALfloat dirGain;
+
+ state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1;
+ state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency);
+ state->Tap[1].delay += state->Tap[0].delay;
+
+ lrpan = Slot->EffectProps.Echo.Spread;
+
+ state->FeedGain = Slot->EffectProps.Echo.Feedback;
+
+ ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
+ 1.0f - Slot->EffectProps.Echo.Damping,
+ (ALfloat)LOWPASSFREQREF/frequency, 0.0f);
+
+ gain = Slot->Gain;
+ dirGain = fabsf(lrpan);
+
+ /* First tap panning */
+ ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]);
+
+ /* Second tap panning */
+ ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]);
+}
+
+static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ const ALuint mask = state->BufferLength-1;
+ const ALuint tap1 = state->Tap[0].delay;
+ const ALuint tap2 = state->Tap[1].delay;
+ ALuint offset = state->Offset;
+ ALfloat smp;
+ ALuint base;
+ ALuint i, k;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64][2];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ for(i = 0;i < td;i++)
+ {
+ /* First tap */
+ temps[i][0] = state->SampleBuffer[(offset-tap1) & mask];
+ /* Second tap */
+ temps[i][1] = state->SampleBuffer[(offset-tap2) & mask];
+
+ // Apply damping and feedback gain to the second tap, and mix in the
+ // new sample
+ smp = ALfilterState_processSingle(&state->Filter, temps[i][1]+SamplesIn[i+base]);
+ state->SampleBuffer[offset&mask] = smp * state->FeedGain;
+ offset++;
+ }
+
+ for(k = 0;k < MaxChannels;k++)
+ {
+ ALfloat gain = state->Gain[0][k];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(i = 0;i < td;i++)
+ SamplesOut[k][i+base] += temps[i][0] * gain;
+ }
+
+ gain = state->Gain[1][k];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(i = 0;i < td;i++)
+ SamplesOut[k][i+base] += temps[i][1] * gain;
+ }
+ }
+
+ base += td;
+ }
+
+ state->Offset = offset;
+}
+
+static void ALechoState_Delete(ALechoState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
+
+
+typedef struct ALechoStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALechoStateFactory;
+
+ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
+{
+ ALechoState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALechoState, ALeffectState, state);
+
+ state->BufferLength = 0;
+ state->SampleBuffer = NULL;
+
+ state->Tap[0].delay = 0;
+ state->Tap[1].delay = 0;
+ state->Offset = 0;
+
+ ALfilterState_clear(&state->Filter);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory);
+
+ALeffectStateFactory *ALechoStateFactory_getFactory(void)
+{
+ static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &EchoFactory);
+}
+
+
+void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALecho_setParami(effect, context, param, vals[0]);
+}
+void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Echo.Delay = val;
+ break;
+
+ case AL_ECHO_LRDELAY:
+ if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Echo.LRDelay = val;
+ break;
+
+ case AL_ECHO_DAMPING:
+ if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Echo.Damping = val;
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Echo.Feedback = val;
+ break;
+
+ case AL_ECHO_SPREAD:
+ if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Echo.Spread = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALecho_setParamf(effect, context, param, vals[0]);
+}
+
+void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALecho_getParami(effect, context, param, vals);
+}
+void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ *val = props->Echo.Delay;
+ break;
+
+ case AL_ECHO_LRDELAY:
+ *val = props->Echo.LRDelay;
+ break;
+
+ case AL_ECHO_DAMPING:
+ *val = props->Echo.Damping;
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ *val = props->Echo.Feedback;
+ break;
+
+ case AL_ECHO_SPREAD:
+ *val = props->Echo.Spread;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALecho_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALecho);
diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c
new file mode 100644
index 00000000..d5bd2caf
--- /dev/null
+++ b/Alc/effects/equalizer.c
@@ -0,0 +1,337 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Mike Gorchak
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+/* The document "Effects Extension Guide.pdf" says that low and high *
+ * frequencies are cutoff frequencies. This is not fully correct, they *
+ * are corner frequencies for low and high shelf filters. If they were *
+ * just cutoff frequencies, there would be no need in cutoff frequency *
+ * gains, which are present. Documentation for "Creative Proteus X2" *
+ * software describes 4-band equalizer functionality in a much better *
+ * way. This equalizer seems to be a predecessor of OpenAL 4-band *
+ * equalizer. With low and high shelf filters we are able to cutoff *
+ * frequencies below and/or above corner frequencies using attenuation *
+ * gains (below 1.0) and amplify all low and/or high frequencies using *
+ * gains above 1.0. *
+ * *
+ * Low-shelf Low Mid Band High Mid Band High-shelf *
+ * corner center center corner *
+ * frequency frequency frequency frequency *
+ * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz *
+ * *
+ * | | | | *
+ * | | | | *
+ * B -----+ /--+--\ /--+--\ +----- *
+ * O |\ | | | | | | /| *
+ * O | \ - | - - | - / | *
+ * S + | \ | | | | | | / | *
+ * T | | | | | | | | | | *
+ * ---------+---------------+------------------+---------------+-------- *
+ * C | | | | | | | | | | *
+ * U - | / | | | | | | \ | *
+ * T | / - | - - | - \ | *
+ * O |/ | | | | | | \| *
+ * F -----+ \--+--/ \--+--/ +----- *
+ * F | | | | *
+ * | | | | *
+ * *
+ * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation *
+ * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in *
+ * octaves for two mid bands. *
+ * *
+ * Implementation is based on the "Cookbook formulae for audio EQ biquad *
+ * filter coefficients" by Robert Bristow-Johnson *
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
+
+typedef struct ALequalizerState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ /* Effect gains for each channel */
+ ALfloat Gain[MaxChannels];
+
+ /* Effect parameters */
+ ALfilterState filter[4];
+} ALequalizerState;
+
+static ALvoid ALequalizerState_Destruct(ALequalizerState *UNUSED(state))
+{
+}
+
+static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
+{
+ return AL_TRUE;
+}
+
+static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot)
+{
+ ALfloat frequency = (ALfloat)device->Frequency;
+ ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
+
+ SetGains(device, gain, state->Gain);
+
+ /* Calculate coefficients for the each type of filter */
+ ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf,
+ sqrtf(slot->EffectProps.Equalizer.LowGain),
+ slot->EffectProps.Equalizer.LowCutoff/frequency,
+ 0.0f);
+
+ ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking,
+ sqrtf(slot->EffectProps.Equalizer.Mid1Gain),
+ slot->EffectProps.Equalizer.Mid1Center/frequency,
+ slot->EffectProps.Equalizer.Mid1Width);
+
+ ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking,
+ sqrtf(slot->EffectProps.Equalizer.Mid2Gain),
+ slot->EffectProps.Equalizer.Mid2Center/frequency,
+ slot->EffectProps.Equalizer.Mid2Width);
+
+ ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf,
+ sqrtf(slot->EffectProps.Equalizer.HighGain),
+ slot->EffectProps.Equalizer.HighCutoff/frequency,
+ 0.0f);
+}
+
+static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ ALuint base;
+ ALuint it;
+ ALuint kt;
+ ALuint ft;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ for(it = 0;it < td;it++)
+ {
+ ALfloat smp = SamplesIn[base+it];
+
+ for(ft = 0;ft < 4;ft++)
+ smp = ALfilterState_processSingle(&state->filter[ft], smp);
+
+ temps[it] = smp;
+ }
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[kt];
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][base+it] += gain * temps[it];
+ }
+
+ base += td;
+ }
+}
+
+static void ALequalizerState_Delete(ALequalizerState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
+
+
+typedef struct ALequalizerStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALequalizerStateFactory;
+
+ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory))
+{
+ ALequalizerState *state;
+ int it;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALequalizerState, ALeffectState, state);
+
+ /* Initialize sample history only on filter creation to avoid */
+ /* sound clicks if filter settings were changed in runtime. */
+ for(it = 0; it < 4; it++)
+ ALfilterState_clear(&state->filter[it]);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory);
+
+ALeffectStateFactory *ALequalizerStateFactory_getFactory(void)
+{
+ static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory);
+}
+
+
+void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALequalizer_setParami(effect, context, param, vals[0]);
+}
+void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EQUALIZER_LOW_GAIN:
+ if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.LowGain = val;
+ break;
+
+ case AL_EQUALIZER_LOW_CUTOFF:
+ if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.LowCutoff = val;
+ break;
+
+ case AL_EQUALIZER_MID1_GAIN:
+ if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid1Gain = val;
+ break;
+
+ case AL_EQUALIZER_MID1_CENTER:
+ if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid1Center = val;
+ break;
+
+ case AL_EQUALIZER_MID1_WIDTH:
+ if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid1Width = val;
+ break;
+
+ case AL_EQUALIZER_MID2_GAIN:
+ if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid2Gain = val;
+ break;
+
+ case AL_EQUALIZER_MID2_CENTER:
+ if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid2Center = val;
+ break;
+
+ case AL_EQUALIZER_MID2_WIDTH:
+ if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.Mid2Width = val;
+ break;
+
+ case AL_EQUALIZER_HIGH_GAIN:
+ if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.HighGain = val;
+ break;
+
+ case AL_EQUALIZER_HIGH_CUTOFF:
+ if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Equalizer.HighCutoff = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALequalizer_setParamf(effect, context, param, vals[0]);
+}
+
+void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALequalizer_getParami(effect, context, param, vals);
+}
+void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EQUALIZER_LOW_GAIN:
+ *val = props->Equalizer.LowGain;
+ break;
+
+ case AL_EQUALIZER_LOW_CUTOFF:
+ *val = props->Equalizer.LowCutoff;
+ break;
+
+ case AL_EQUALIZER_MID1_GAIN:
+ *val = props->Equalizer.Mid1Gain;
+ break;
+
+ case AL_EQUALIZER_MID1_CENTER:
+ *val = props->Equalizer.Mid1Center;
+ break;
+
+ case AL_EQUALIZER_MID1_WIDTH:
+ *val = props->Equalizer.Mid1Width;
+ break;
+
+ case AL_EQUALIZER_MID2_GAIN:
+ *val = props->Equalizer.Mid2Gain;
+ break;
+
+ case AL_EQUALIZER_MID2_CENTER:
+ *val = props->Equalizer.Mid2Center;
+ break;
+
+ case AL_EQUALIZER_MID2_WIDTH:
+ *val = props->Equalizer.Mid2Width;
+ break;
+
+ case AL_EQUALIZER_HIGH_GAIN:
+ *val = props->Equalizer.HighGain;
+ break;
+
+ case AL_EQUALIZER_HIGH_CUTOFF:
+ *val = props->Equalizer.HighCutoff;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALequalizer_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALequalizer);
diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c
new file mode 100644
index 00000000..a94cd365
--- /dev/null
+++ b/Alc/effects/flanger.c
@@ -0,0 +1,380 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2013 by Mike Gorchak
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALflangerState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ ALfloat *SampleBuffer[2];
+ ALuint BufferLength;
+ ALuint offset;
+ ALuint lfo_range;
+ ALfloat lfo_scale;
+ ALint lfo_disp;
+
+ /* Gains for left and right sides */
+ ALfloat Gain[2][MaxChannels];
+
+ /* effect parameters */
+ ALint waveform;
+ ALint delay;
+ ALfloat depth;
+ ALfloat feedback;
+} ALflangerState;
+
+static ALvoid ALflangerState_Destruct(ALflangerState *state)
+{
+ free(state->SampleBuffer[0]);
+ state->SampleBuffer[0] = NULL;
+ state->SampleBuffer[1] = NULL;
+}
+
+static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
+{
+ ALuint maxlen;
+ ALuint it;
+
+ maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1;
+ maxlen = NextPowerOf2(maxlen);
+
+ if(maxlen != state->BufferLength)
+ {
+ void *temp;
+
+ temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2);
+ if(!temp) return AL_FALSE;
+ state->SampleBuffer[0] = temp;
+ state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
+
+ state->BufferLength = maxlen;
+ }
+
+ for(it = 0;it < state->BufferLength;it++)
+ {
+ state->SampleBuffer[0][it] = 0.0f;
+ state->SampleBuffer[1][it] = 0.0f;
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALfloat frequency = (ALfloat)Device->Frequency;
+ ALfloat rate;
+ ALint phase;
+
+ state->waveform = Slot->EffectProps.Flanger.Waveform;
+ state->depth = Slot->EffectProps.Flanger.Depth;
+ state->feedback = Slot->EffectProps.Flanger.Feedback;
+ state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
+
+ /* Gains for left and right sides */
+ ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
+ ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+
+ phase = Slot->EffectProps.Flanger.Phase;
+ rate = Slot->EffectProps.Flanger.Rate;
+ if(!(rate > 0.0f))
+ {
+ state->lfo_scale = 0.0f;
+ state->lfo_range = 1;
+ state->lfo_disp = 0;
+ }
+ else
+ {
+ /* Calculate LFO coefficient */
+ state->lfo_range = fastf2u(frequency/rate + 0.5f);
+ switch(state->waveform)
+ {
+ case AL_FLANGER_WAVEFORM_TRIANGLE:
+ state->lfo_scale = 4.0f / state->lfo_range;
+ break;
+ case AL_FLANGER_WAVEFORM_SINUSOID:
+ state->lfo_scale = F_2PI / state->lfo_range;
+ break;
+ }
+
+ /* Calculate lfo phase displacement */
+ state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
+ }
+}
+
+static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
+{
+ ALfloat lfo_value;
+
+ lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_left = fastf2i(lfo_value) + state->delay;
+
+ offset += state->lfo_disp;
+ lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_right = fastf2i(lfo_value) + state->delay;
+}
+
+static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
+{
+ ALfloat lfo_value;
+
+ lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_left = fastf2i(lfo_value) + state->delay;
+
+ offset += state->lfo_disp;
+ lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
+ lfo_value *= state->depth * state->delay;
+ *delay_right = fastf2i(lfo_value) + state->delay;
+}
+
+#define DECL_TEMPLATE(Func) \
+static void Process##Func(ALflangerState *state, const ALuint SamplesToDo, \
+ const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
+{ \
+ const ALuint bufmask = state->BufferLength-1; \
+ ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
+ ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
+ ALuint offset = state->offset; \
+ const ALfloat feedback = state->feedback; \
+ ALuint it; \
+ \
+ for(it = 0;it < SamplesToDo;it++) \
+ { \
+ ALint delay_left, delay_right; \
+ Func(&delay_left, &delay_right, offset, state); \
+ \
+ out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
+ leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \
+ \
+ out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
+ rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \
+ \
+ offset++; \
+ } \
+ state->offset = offset; \
+}
+
+DECL_TEMPLATE(Triangle)
+DECL_TEMPLATE(Sinusoid)
+
+#undef DECL_TEMPLATE
+
+static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ ALuint it, kt;
+ ALuint base;
+
+ for(base = 0;base < SamplesToDo;)
+ {
+ ALfloat temps[64][2];
+ ALuint td = minu(SamplesToDo-base, 64);
+
+ if(state->waveform == AL_FLANGER_WAVEFORM_TRIANGLE)
+ ProcessTriangle(state, td, SamplesIn+base, temps);
+ else if(state->waveform == AL_FLANGER_WAVEFORM_SINUSOID)
+ ProcessSinusoid(state, td, SamplesIn+base, temps);
+
+ for(kt = 0;kt < MaxChannels;kt++)
+ {
+ ALfloat gain = state->Gain[0][kt];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][it+base] += temps[it][0] * gain;
+ }
+
+ gain = state->Gain[1][kt];
+ if(gain > GAIN_SILENCE_THRESHOLD)
+ {
+ for(it = 0;it < td;it++)
+ SamplesOut[kt][it+base] += temps[it][1] * gain;
+ }
+ }
+
+ base += td;
+ }
+}
+
+static void ALflangerState_Delete(ALflangerState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
+
+
+typedef struct ALflangerStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALflangerStateFactory;
+
+ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
+{
+ ALflangerState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALflangerState, ALeffectState, state);
+
+ state->BufferLength = 0;
+ state->SampleBuffer[0] = NULL;
+ state->SampleBuffer[1] = NULL;
+ state->offset = 0;
+ state->lfo_range = 1;
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
+
+ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
+{
+ static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
+}
+
+
+void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_FLANGER_WAVEFORM:
+ if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Waveform = val;
+ break;
+
+ case AL_FLANGER_PHASE:
+ if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Phase = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALflanger_setParami(effect, context, param, vals[0]);
+}
+void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_FLANGER_RATE:
+ if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Rate = val;
+ break;
+
+ case AL_FLANGER_DEPTH:
+ if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Depth = val;
+ break;
+
+ case AL_FLANGER_FEEDBACK:
+ if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Feedback = val;
+ break;
+
+ case AL_FLANGER_DELAY:
+ if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Flanger.Delay = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALflanger_setParamf(effect, context, param, vals[0]);
+}
+
+void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_FLANGER_WAVEFORM:
+ *val = props->Flanger.Waveform;
+ break;
+
+ case AL_FLANGER_PHASE:
+ *val = props->Flanger.Phase;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALflanger_getParami(effect, context, param, vals);
+}
+void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_FLANGER_RATE:
+ *val = props->Flanger.Rate;
+ break;
+
+ case AL_FLANGER_DEPTH:
+ *val = props->Flanger.Depth;
+ break;
+
+ case AL_FLANGER_FEEDBACK:
+ *val = props->Flanger.Feedback;
+ break;
+
+ case AL_FLANGER_DELAY:
+ *val = props->Flanger.Delay;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALflanger_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALflanger);
diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c
new file mode 100644
index 00000000..17ca7e17
--- /dev/null
+++ b/Alc/effects/modulator.c
@@ -0,0 +1,306 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALmodulatorState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ enum {
+ SINUSOID,
+ SAWTOOTH,
+ SQUARE
+ } Waveform;
+
+ ALuint index;
+ ALuint step;
+
+ ALfloat Gain[MaxChannels];
+
+ ALfilterState Filter;
+} ALmodulatorState;
+
+#define WAVEFORM_FRACBITS 24
+#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
+#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
+
+static inline ALfloat Sin(ALuint index)
+{
+ return sinf(index*(F_2PI/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
+}
+
+static inline ALfloat Saw(ALuint index)
+{
+ return (ALfloat)index / WAVEFORM_FRACONE;
+}
+
+static inline ALfloat Square(ALuint index)
+{
+ return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
+}
+
+#define DECL_TEMPLATE(func) \
+static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
+ const ALfloat *restrict SamplesIn, \
+ ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \
+{ \
+ const ALuint step = state->step; \
+ ALuint index = state->index; \
+ ALuint base; \
+ \
+ for(base = 0;base < SamplesToDo;) \
+ { \
+ ALfloat temps[64]; \
+ ALuint td = minu(SamplesToDo-base, 64); \
+ ALuint i, k; \
+ \
+ for(i = 0;i < td;i++) \
+ { \
+ ALfloat samp; \
+ samp = SamplesIn[base+i]; \
+ samp = ALfilterState_processSingle(&state->Filter, samp); \
+ \
+ index += step; \
+ index &= WAVEFORM_FRACMASK; \
+ temps[i] = samp * func(index); \
+ } \
+ \
+ for(k = 0;k < MaxChannels;k++) \
+ { \
+ ALfloat gain = state->Gain[k]; \
+ if(!(gain > GAIN_SILENCE_THRESHOLD)) \
+ continue; \
+ \
+ for(i = 0;i < td;i++) \
+ SamplesOut[k][base+i] += gain * temps[i]; \
+ } \
+ \
+ base += td; \
+ } \
+ state->index = index; \
+}
+
+DECL_TEMPLATE(Sin)
+DECL_TEMPLATE(Saw)
+DECL_TEMPLATE(Square)
+
+#undef DECL_TEMPLATE
+
+
+static ALvoid ALmodulatorState_Destruct(ALmodulatorState *UNUSED(state))
+{
+}
+
+static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
+{
+ return AL_TRUE;
+}
+
+static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot)
+{
+ ALfloat gain, cw, a;
+
+ if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
+ state->Waveform = SINUSOID;
+ else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
+ state->Waveform = SAWTOOTH;
+ else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)
+ state->Waveform = SQUARE;
+
+ state->step = fastf2u(Slot->EffectProps.Modulator.Frequency*WAVEFORM_FRACONE /
+ Device->Frequency);
+ if(state->step == 0) state->step = 1;
+
+ /* Custom filter coeffs, which match the old version instead of a low-shelf. */
+ cw = cosf(F_2PI * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
+ a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
+
+ state->Filter.b[0] = a;
+ state->Filter.b[1] = -a;
+ state->Filter.b[2] = 0.0f;
+ state->Filter.a[0] = 1.0f;
+ state->Filter.a[1] = -a;
+ state->Filter.a[2] = 0.0f;
+
+ gain = sqrtf(1.0f/Device->NumChan) * Slot->Gain;
+ SetGains(Device, gain, state->Gain);
+}
+
+static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ switch(state->Waveform)
+ {
+ case SINUSOID:
+ ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut);
+ break;
+
+ case SAWTOOTH:
+ ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut);
+ break;
+
+ case SQUARE:
+ ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut);
+ break;
+ }
+}
+
+static void ALmodulatorState_Delete(ALmodulatorState *state)
+{
+ free(state);
+}
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
+
+
+typedef struct ALmodulatorStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALmodulatorStateFactory;
+
+static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory))
+{
+ ALmodulatorState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state) return NULL;
+ SET_VTABLE2(ALmodulatorState, ALeffectState, state);
+
+ state->index = 0;
+ state->step = 1;
+
+ ALfilterState_clear(&state->Filter);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory);
+
+ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void)
+{
+ static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory);
+}
+
+
+void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Modulator.Frequency = val;
+ break;
+
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Modulator.HighPassCutoff = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALmodulator_setParamf(effect, context, param, vals[0]);
+}
+void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ ALmodulator_setParamf(effect, context, param, (ALfloat)val);
+ break;
+
+ case AL_RING_MODULATOR_WAVEFORM:
+ if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Modulator.Waveform = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALmodulator_setParami(effect, context, param, vals[0]);
+}
+
+void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ *val = (ALint)props->Modulator.Frequency;
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *val = (ALint)props->Modulator.HighPassCutoff;
+ break;
+ case AL_RING_MODULATOR_WAVEFORM:
+ *val = props->Modulator.Waveform;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALmodulator_getParami(effect, context, param, vals);
+}
+void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ *val = props->Modulator.Frequency;
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *val = props->Modulator.HighPassCutoff;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALmodulator_getParamf(effect, context, param, vals);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALmodulator);
diff --git a/Alc/effects/null.c b/Alc/effects/null.c
new file mode 100644
index 00000000..816a2525
--- /dev/null
+++ b/Alc/effects/null.c
@@ -0,0 +1,155 @@
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+
+
+typedef struct ALnullState {
+ DERIVE_FROM_TYPE(ALeffectState);
+} ALnullState;
+
+
+/* This destructs (not free!) the effect state. It's called only when the
+ * effect slot is no longer used.
+ */
+static ALvoid ALnullState_Destruct(ALnullState* UNUSED(state))
+{
+}
+
+/* This updates the device-dependant effect state. This is called on
+ * initialization and any time the device parameters (eg. playback frequency,
+ * format) have been changed.
+ */
+static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device))
+{
+ return AL_TRUE;
+}
+
+/* This updates the effect state. This is called any time the effect is
+ * (re)loaded into a slot.
+ */
+static ALvoid ALnullState_update(ALnullState* UNUSED(state), ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot))
+{
+}
+
+/* This processes the effect state, for the given number of samples from the
+ * input to the output buffer. The result should be added to the output buffer,
+ * not replace it.
+ */
+static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloat (*restrict samplesOut)[BUFFERSIZE])
+{
+ /* NOTE: Couldn't use the UNUSED macro on samplesOut due to the way GCC's
+ * __attribute__ declaration interacts with the parenthesis. */
+ (void)samplesOut;
+}
+
+/* This frees the memory used by the object, after it has been destructed. */
+static void ALnullState_Delete(ALnullState *state)
+{
+ free(state);
+}
+
+/* Define the forwards and the ALeffectState vtable for this type. */
+DEFINE_ALEFFECTSTATE_VTABLE(ALnullState);
+
+
+typedef struct ALnullStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALnullStateFactory;
+
+/* Creates ALeffectState objects of the appropriate type. */
+ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
+{
+ ALnullState *state;
+
+ state = calloc(1, sizeof(*state));
+ if(!state) return NULL;
+ /* Set vtables for inherited types. */
+ SET_VTABLE2(ALnullState, ALeffectState, state);
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+/* Define the ALeffectStateFactory vtable for this type. */
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory);
+
+ALeffectStateFactory *ALnullStateFactory_getFactory(void)
+{
+ static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &NullFactory);
+}
+
+
+void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_setParamiv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_setParamf(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_setParamfv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+
+void ALnull_getParami(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_getParamiv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_getParamf(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALnull_getParamfv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals))
+{
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+
+DEFINE_ALEFFECT_VTABLE(ALnull);
diff --git a/Alc/alcReverb.c b/Alc/effects/reverb.c
index b7dcdab9..75ec76e3 100644
--- a/Alc/alcReverb.c
+++ b/Alc/effects/reverb.c
@@ -31,6 +31,7 @@
#include "alFilter.h"
#include "alError.h"
+
typedef struct DelayLine
{
// The delay lines use sample lengths that are powers of 2 to allow the
@@ -39,18 +40,19 @@ typedef struct DelayLine
ALfloat *Line;
} DelayLine;
-typedef struct ALverbState {
- // Must be first in all effects!
- ALeffectState state;
+typedef struct ALreverbState {
+ DERIVE_FROM_TYPE(ALeffectState);
+
+ ALboolean IsEax;
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and management code.
ALfloat *SampleBuffer;
ALuint TotalSamples;
- // Master effect low-pass filter (2 chained 1-pole filters).
- FILTER LpFilter;
- ALfloat LpHistory[2];
+ // Master effect filters
+ ALfilterState LpFilter;
+ ALfilterState HpFilter; // EAX only
struct {
// Modulator delay line.
@@ -160,7 +162,7 @@ typedef struct ALverbState {
/* Temporary storage used when processing, before deinterlacing. */
ALfloat ReverbSamples[BUFFERSIZE][4];
ALfloat EarlySamples[BUFFERSIZE][4];
-} ALverbState;
+} ALreverbState;
/* This is a user config option for modifying the overall output of the reverb
* effect.
@@ -222,24 +224,24 @@ static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
// Basic delay line input/output routines.
-static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
+static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
{
return Delay->Line[offset&Delay->Mask];
}
-static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
+static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
{
Delay->Line[offset&Delay->Mask] = in;
}
// Attenuated delay line output routine.
-static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
+static inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
{
return coeff * Delay->Line[offset&Delay->Mask];
}
// Basic attenuated all-pass input/output routine.
-static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
+static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
{
ALfloat out, feed;
@@ -255,7 +257,7 @@ static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint
// Given an input sample, this function produces modulation for the late
// reverb.
-static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
+static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in)
{
ALfloat sinus, frac;
ALuint offset;
@@ -264,7 +266,7 @@ static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
// Calculate the sinus rythm (dependent on modulation time and the
// sampling rate). The center of the sinus is moved to reduce the delay
// of the effect when the time or depth are low.
- sinus = 1.0f - cosf(F_PI*2.0f * State->Mod.Index / State->Mod.Range);
+ sinus = 1.0f - cosf(F_2PI * State->Mod.Index / State->Mod.Range);
// The depth determines the range over which to read the input samples
// from, so it must be filtered to reduce the distortion caused by even
@@ -292,7 +294,7 @@ static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
}
// Delay line output routine for early reflections.
-static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
+static inline ALfloat EarlyDelayLineOut(ALreverbState *State, ALuint index)
{
return AttenuatedDelayLineOut(&State->Early.Delay[index],
State->Offset - State->Early.Offset[index],
@@ -301,7 +303,7 @@ static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
// Given an input sample, this function produces four-channel output for the
// early reflections.
-static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *RESTRICT out)
+static inline ALvoid EarlyReflection(ALreverbState *State, ALfloat in, ALfloat *restrict out)
{
ALfloat d[4], v, f[4];
@@ -346,7 +348,7 @@ static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *
}
// All-pass input/output routine for late reverb.
-static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
+static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint index, ALfloat in)
{
return AllpassInOut(&State->Late.ApDelay[index],
State->Offset - State->Late.ApOffset[index],
@@ -355,7 +357,7 @@ static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALflo
}
// Delay line output routine for late reverb.
-static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
+static inline ALfloat LateDelayLineOut(ALreverbState *State, ALuint index)
{
return AttenuatedDelayLineOut(&State->Late.Delay[index],
State->Offset - State->Late.Offset[index],
@@ -363,7 +365,7 @@ static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
}
// Low-pass filter input/output routine for late reverb.
-static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
+static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in)
{
in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
State->Late.LpSample[index] = in;
@@ -372,7 +374,7 @@ static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALflo
// Given four decorrelated input samples, this function produces four-channel
// output for the late reverb.
-static __inline ALvoid LateReverb(ALverbState *State, const ALfloat *RESTRICT in, ALfloat *RESTRICT out)
+static inline ALvoid LateReverb(ALreverbState *State, const ALfloat *restrict in, ALfloat *restrict out)
{
ALfloat d[4], f[4];
@@ -443,7 +445,7 @@ static __inline ALvoid LateReverb(ALverbState *State, const ALfloat *RESTRICT in
// Given an input sample, this function mixes echo into the four-channel late
// reverb.
-static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *RESTRICT late)
+static inline ALvoid EAXEcho(ALreverbState *State, ALfloat in, ALfloat *restrict late)
{
ALfloat out, feed;
@@ -477,12 +479,12 @@ static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *RESTRICT
// Perform the non-EAX reverb pass on a given input sample, resulting in
// four-channel output.
-static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *RESTRICT out)
+static inline ALvoid VerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict out)
{
ALfloat feed, late[4], taps[4];
- // Low-pass filter the incoming sample.
- in = lpFilter2P(&State->LpFilter, 0, in);
+ // Filter the incoming sample.
+ in = ALfilterState_processSingle(&State->LpFilter, in);
// Feed the initial delay line.
DelayLineIn(&State->Delay, State->Offset, in);
@@ -516,12 +518,13 @@ static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *RESTRIC
// Perform the EAX reverb pass on a given input sample, resulting in four-
// channel output.
-static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *RESTRICT early, ALfloat *RESTRICT late)
+static inline ALvoid EAXVerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict early, ALfloat *restrict late)
{
ALfloat feed, taps[4];
// Low-pass filter the incoming sample.
- in = lpFilter2P(&State->LpFilter, 0, in);
+ in = ALfilterState_processSingle(&State->LpFilter, in);
+ in = ALfilterState_processSingle(&State->HpFilter, in);
// Perform any modulation on the input.
in = EAXModulation(State, in);
@@ -553,12 +556,9 @@ static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *REST
State->Offset++;
}
-// This processes the reverb state, given the input samples and an output
-// buffer.
-static ALvoid VerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
+static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
{
- ALverbState *State = (ALverbState*)effect;
- ALfloat (*RESTRICT out)[4] = State->ReverbSamples;
+ ALfloat (*restrict out)[4] = State->ReverbSamples;
ALuint index, c;
/* Process reverb for these samples. */
@@ -568,21 +568,18 @@ static ALvoid VerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALflo
for(c = 0;c < MaxChannels;c++)
{
ALfloat gain = State->Gain[c];
- if(gain > 0.00001f)
- {
- for(index = 0;index < SamplesToDo;index++)
- SamplesOut[c][index] += gain * out[index][c&3];
- }
+ if(!(gain > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(index = 0;index < SamplesToDo;index++)
+ SamplesOut[c][index] += gain * out[index][c&3];
}
}
-// This processes the EAX reverb state, given the input samples and an output
-// buffer.
-static ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
+static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
{
- ALverbState *State = (ALverbState*)effect;
- ALfloat (*RESTRICT early)[4] = State->EarlySamples;
- ALfloat (*RESTRICT late)[4] = State->ReverbSamples;
+ ALfloat (*restrict early)[4] = State->EarlySamples;
+ ALfloat (*restrict late)[4] = State->ReverbSamples;
ALuint index, c;
/* Process reverb for these samples. */
@@ -591,15 +588,16 @@ static ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const AL
for(c = 0;c < MaxChannels;c++)
{
- ALfloat earlyGain = State->Early.PanGain[c];
- ALfloat lateGain = State->Late.PanGain[c];
+ ALfloat earlyGain, lateGain;
- if(earlyGain > 0.00001f)
+ earlyGain = State->Early.PanGain[c];
+ if(earlyGain > GAIN_SILENCE_THRESHOLD)
{
for(index = 0;index < SamplesToDo;index++)
SamplesOut[c][index] += earlyGain*early[index][c&3];
}
- if(lateGain > 0.00001f)
+ lateGain = State->Late.PanGain[c];
+ if(lateGain > GAIN_SILENCE_THRESHOLD)
{
for(index = 0;index < SamplesToDo;index++)
SamplesOut[c][index] += lateGain*late[index][c&3];
@@ -607,10 +605,17 @@ static ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const AL
}
}
+static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+{
+ if(State->IsEax)
+ ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut);
+ else
+ ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut);
+}
// Given the allocated sample buffer, this function updates each delay line
// offset.
-static __inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
+static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
{
Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
}
@@ -634,7 +639,7 @@ static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequenc
* for all lines given the sample rate (frequency). If an allocation failure
* occurs, it returns AL_FALSE.
*/
-static ALboolean AllocLines(ALuint frequency, ALverbState *State)
+static ALboolean AllocLines(ALuint frequency, ALreverbState *State)
{
ALuint totalSamples, index;
ALfloat length;
@@ -722,12 +727,8 @@ static ALboolean AllocLines(ALuint frequency, ALverbState *State)
return AL_TRUE;
}
-// This updates the device-dependant EAX reverb state. This is called on
-// initialization and any time the device parameters (eg. playback frequency,
-// format) have been changed.
-static ALboolean ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device)
{
- ALverbState *State = (ALverbState*)effect;
ALuint frequency = Device->Frequency, index;
// Allocate the delay lines.
@@ -760,28 +761,21 @@ static ALboolean ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
// Calculate a decay coefficient given the length of each cycle and the time
// until the decay reaches -60 dB.
-static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
+static inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
{
return powf(0.001f/*-60 dB*/, length/decayTime);
}
// Calculate a decay length from a coefficient and the time until the decay
// reaches -60 dB.
-static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
+static inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
{
return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/;
}
-// Calculate the high frequency parameter for the I3DL2 coefficient
-// calculation.
-static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
-{
- return cosf(F_PI*2.0f * hfRef / frequency);
-}
-
// Calculate an attenuation to be applied to the input of any echo models to
// compensate for modal density and decay time.
-static __inline ALfloat CalcDensityGain(ALfloat a)
+static inline ALfloat CalcDensityGain(ALfloat a)
{
/* The energy of a signal can be obtained by finding the area under the
* squared signal. This takes the form of Sum(x_n^2), where x is the
@@ -800,7 +794,7 @@ static __inline ALfloat CalcDensityGain(ALfloat a)
}
// Calculate the mixing matrix coefficients given a diffusion factor.
-static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
+static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
{
ALfloat n, t;
@@ -835,7 +829,7 @@ static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF,
// Calculate the coefficient for a HF (and eventually LF) decay damping
// filter.
-static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
+static inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
{
ALfloat coeff, g;
@@ -850,7 +844,14 @@ static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloa
// Damping is done with a 1-pole filter, so g needs to be squared.
g *= g;
- coeff = lpCoeffCalc(g, cw);
+ if(g < 0.9999f) /* 1-epsilon */
+ {
+ /* Be careful with gains < 0.001, as that causes the coefficient
+ * head towards 1, which will flatten the signal. */
+ g = maxf(g, 0.001f);
+ coeff = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) /
+ (1 - g);
+ }
// Very low decay times will produce minimal output, so apply an
// upper bound to the coefficient.
@@ -862,7 +863,7 @@ static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloa
// Update the EAX modulation index, range, and depth. Keep in mind that this
// kind of vibrato is additive and not multiplicative as one may expect. The
// downswing will sound stronger than the upswing.
-static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
+static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALreverbState *State)
{
ALuint range;
@@ -892,7 +893,7 @@ static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequenc
}
// Update the offsets for the initial effect delay line.
-static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
+static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State)
{
// Calculate the initial delay taps.
State->DelayTap[0] = fastf2u(earlyDelay * frequency);
@@ -900,7 +901,7 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint freq
}
// Update the early reflections gain and line coefficients.
-static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
+static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State)
{
ALuint index;
@@ -917,7 +918,7 @@ static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat la
}
// Update the offsets for the decorrelator line.
-static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
+static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State)
{
ALuint index;
ALfloat length;
@@ -938,7 +939,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState
}
// Update the late reverb gains, line lengths, and line coefficients.
-static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
{
ALfloat length;
ALuint index;
@@ -996,7 +997,7 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
// Update the echo gain, line offset, line coefficients, and mixing
// coefficients.
-static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
{
// Update the offset and coefficient for the echo delay line.
State->Echo.Offset = fastf2u(echoTime * frequency);
@@ -1028,7 +1029,7 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT
}
// Update the early and late 3D panning gains.
-static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State)
+static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State)
{
ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
ReflectionsPan[2] };
@@ -1037,7 +1038,6 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
ALfloat ambientGain;
ALfloat dirGain;
ALfloat length;
- ALuint index;
Gain *= ReverbBoost;
@@ -1063,221 +1063,720 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
}
dirGain = sqrtf(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]);
- for(index = 0;index < MaxChannels;index++)
- State->Early.PanGain[index] = 0.0f;
ComputeAngleGains(Device, atan2f(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI,
lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain);
dirGain = sqrtf(latePan[0]*latePan[0] + latePan[2]*latePan[2]);
- for(index = 0;index < MaxChannels;index++)
- State->Late.PanGain[index] = 0.0f;
ComputeAngleGains(Device, atan2f(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI,
lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain);
}
-// This updates the EAX reverb state. This is called any time the EAX reverb
-// effect is loaded into a slot.
-static ALvoid ReverbUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot)
+static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot)
{
- ALverbState *State = (ALverbState*)effect;
ALuint frequency = Device->Frequency;
- ALboolean isEAX = AL_FALSE;
- ALfloat cw, x, y, hfRatio;
+ ALfloat lfscale, hfscale, hfRatio;
+ ALfloat cw, x, y;
+
+ if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
+ State->IsEax = AL_TRUE;
+ else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
+ State->IsEax = AL_FALSE;
- if(Slot->effect.type == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
+ // Calculate the master low-pass filter (from the master effect HF gain).
+ if(State->IsEax)
{
- State->state.Process = EAXVerbProcess;
- isEAX = AL_TRUE;
+ hfscale = Slot->EffectProps.Reverb.HFReference / frequency;
+ ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
+ Slot->EffectProps.Reverb.GainHF,
+ hfscale, 0.0f);
+ lfscale = Slot->EffectProps.Reverb.LFReference / frequency;
+ ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf,
+ Slot->EffectProps.Reverb.GainLF,
+ lfscale, 0.0f);
}
- else if(Slot->effect.type == AL_EFFECT_REVERB || EmulateEAXReverb)
+ else
{
- State->state.Process = VerbProcess;
- isEAX = AL_FALSE;
+ hfscale = (ALfloat)LOWPASSFREQREF / frequency;
+ ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
+ Slot->EffectProps.Reverb.GainHF,
+ hfscale, 0.0f);
}
- // Calculate the master low-pass filter (from the master effect HF gain).
- if(isEAX) cw = CalcI3DL2HFreq(Slot->effect.Reverb.HFReference, frequency);
- else cw = CalcI3DL2HFreq(LOWPASSFREQREF, frequency);
- // This is done with 2 chained 1-pole filters, so no need to square g.
- State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Reverb.GainHF, cw);
-
- if(isEAX)
+ if(State->IsEax)
{
// Update the modulator line.
- UpdateModulator(Slot->effect.Reverb.ModulationTime,
- Slot->effect.Reverb.ModulationDepth,
+ UpdateModulator(Slot->EffectProps.Reverb.ModulationTime,
+ Slot->EffectProps.Reverb.ModulationDepth,
frequency, State);
}
// Update the initial effect delay.
- UpdateDelayLine(Slot->effect.Reverb.ReflectionsDelay,
- Slot->effect.Reverb.LateReverbDelay,
+ UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay,
+ Slot->EffectProps.Reverb.LateReverbDelay,
frequency, State);
// Update the early lines.
- UpdateEarlyLines(Slot->effect.Reverb.Gain,
- Slot->effect.Reverb.ReflectionsGain,
- Slot->effect.Reverb.LateReverbDelay, State);
+ UpdateEarlyLines(Slot->EffectProps.Reverb.Gain,
+ Slot->EffectProps.Reverb.ReflectionsGain,
+ Slot->EffectProps.Reverb.LateReverbDelay, State);
// Update the decorrelator.
- UpdateDecorrelator(Slot->effect.Reverb.Density, frequency, State);
+ UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State);
// Get the mixing matrix coefficients (x and y).
- CalcMatrixCoeffs(Slot->effect.Reverb.Diffusion, &x, &y);
+ CalcMatrixCoeffs(Slot->EffectProps.Reverb.Diffusion, &x, &y);
// Then divide x into y to simplify the matrix calculation.
State->Late.MixCoeff = y / x;
// If the HF limit parameter is flagged, calculate an appropriate limit
// based on the air absorption parameter.
- hfRatio = Slot->effect.Reverb.DecayHFRatio;
- if(Slot->effect.Reverb.DecayHFLimit &&
- Slot->effect.Reverb.AirAbsorptionGainHF < 1.0f)
+ hfRatio = Slot->EffectProps.Reverb.DecayHFRatio;
+ if(Slot->EffectProps.Reverb.DecayHFLimit &&
+ Slot->EffectProps.Reverb.AirAbsorptionGainHF < 1.0f)
hfRatio = CalcLimitedHfRatio(hfRatio,
- Slot->effect.Reverb.AirAbsorptionGainHF,
- Slot->effect.Reverb.DecayTime);
+ Slot->EffectProps.Reverb.AirAbsorptionGainHF,
+ Slot->EffectProps.Reverb.DecayTime);
+ cw = cosf(F_2PI * hfscale);
// Update the late lines.
- UpdateLateLines(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain,
- x, Slot->effect.Reverb.Density, Slot->effect.Reverb.DecayTime,
- Slot->effect.Reverb.Diffusion, hfRatio, cw, frequency, State);
+ UpdateLateLines(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
+ x, Slot->EffectProps.Reverb.Density, Slot->EffectProps.Reverb.DecayTime,
+ Slot->EffectProps.Reverb.Diffusion, hfRatio, cw, frequency, State);
- if(isEAX)
+ if(State->IsEax)
{
// Update the echo line.
- UpdateEchoLine(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain,
- Slot->effect.Reverb.EchoTime, Slot->effect.Reverb.DecayTime,
- Slot->effect.Reverb.Diffusion, Slot->effect.Reverb.EchoDepth,
+ UpdateEchoLine(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
+ Slot->EffectProps.Reverb.EchoTime, Slot->EffectProps.Reverb.DecayTime,
+ Slot->EffectProps.Reverb.Diffusion, Slot->EffectProps.Reverb.EchoDepth,
hfRatio, cw, frequency, State);
// Update early and late 3D panning.
- Update3DPanning(Device, Slot->effect.Reverb.ReflectionsPan,
- Slot->effect.Reverb.LateReverbPan, Slot->Gain, State);
+ Update3DPanning(Device, Slot->EffectProps.Reverb.ReflectionsPan,
+ Slot->EffectProps.Reverb.LateReverbPan, Slot->Gain, State);
}
else
{
- ALfloat gain = Slot->Gain;
- ALuint index;
-
/* Update channel gains */
- gain *= sqrtf(2.0f/Device->NumChan) * ReverbBoost;
- for(index = 0;index < MaxChannels;index++)
- State->Gain[index] = 0.0f;
- for(index = 0;index < Device->NumChan;index++)
- {
- enum Channel chan = Device->Speaker2Chan[index];
- State->Gain[chan] = gain;
- }
+ ALfloat gain = sqrtf(2.0f/Device->NumChan) * ReverbBoost * Slot->Gain;
+ SetGains(Device, gain, State->Gain);
}
}
-// This destroys the reverb state. It should be called only when the effect
-// slot has a different (or no) effect loaded over the reverb effect.
-static ALvoid ReverbDestroy(ALeffectState *effect)
+
+static ALvoid ALreverbState_Destruct(ALreverbState *State)
{
- ALverbState *State = (ALverbState*)effect;
- if(State)
- {
- free(State->SampleBuffer);
- State->SampleBuffer = NULL;
- free(State);
- }
+ free(State->SampleBuffer);
+ State->SampleBuffer = NULL;
}
-// This creates the reverb state. It should be called only when the reverb
-// effect is loaded into a slot that doesn't already have a reverb effect.
-ALeffectState *ReverbCreate(void)
+static void ALreverbState_Delete(ALreverbState *state)
{
- ALverbState *State = NULL;
- ALuint index;
+ free(state);
+}
- State = malloc(sizeof(ALverbState));
- if(!State)
- return NULL;
+DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
- State->state.Destroy = ReverbDestroy;
- State->state.DeviceUpdate = ReverbDeviceUpdate;
- State->state.Update = ReverbUpdate;
- State->state.Process = VerbProcess;
- State->TotalSamples = 0;
- State->SampleBuffer = NULL;
+typedef struct ALreverbStateFactory {
+ DERIVE_FROM_TYPE(ALeffectStateFactory);
+} ALreverbStateFactory;
+
+static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
+{
+ ALreverbState *state;
+ ALuint index;
+
+ state = malloc(sizeof(ALreverbState));
+ if(!state) return NULL;
+ SET_VTABLE2(ALreverbState, ALeffectState, state);
- State->LpFilter.coeff = 0.0f;
- State->LpFilter.history[0] = 0.0f;
- State->LpFilter.history[1] = 0.0f;
+ state->TotalSamples = 0;
+ state->SampleBuffer = NULL;
- State->Mod.Delay.Mask = 0;
- State->Mod.Delay.Line = NULL;
- State->Mod.Index = 0;
- State->Mod.Range = 1;
- State->Mod.Depth = 0.0f;
- State->Mod.Coeff = 0.0f;
- State->Mod.Filter = 0.0f;
+ ALfilterState_clear(&state->LpFilter);
+ ALfilterState_clear(&state->HpFilter);
- State->Delay.Mask = 0;
- State->Delay.Line = NULL;
- State->DelayTap[0] = 0;
- State->DelayTap[1] = 0;
+ state->Mod.Delay.Mask = 0;
+ state->Mod.Delay.Line = NULL;
+ state->Mod.Index = 0;
+ state->Mod.Range = 1;
+ state->Mod.Depth = 0.0f;
+ state->Mod.Coeff = 0.0f;
+ state->Mod.Filter = 0.0f;
- State->Early.Gain = 0.0f;
+ state->Delay.Mask = 0;
+ state->Delay.Line = NULL;
+ state->DelayTap[0] = 0;
+ state->DelayTap[1] = 0;
+
+ state->Early.Gain = 0.0f;
for(index = 0;index < 4;index++)
{
- State->Early.Coeff[index] = 0.0f;
- State->Early.Delay[index].Mask = 0;
- State->Early.Delay[index].Line = NULL;
- State->Early.Offset[index] = 0;
+ state->Early.Coeff[index] = 0.0f;
+ state->Early.Delay[index].Mask = 0;
+ state->Early.Delay[index].Line = NULL;
+ state->Early.Offset[index] = 0;
}
- State->Decorrelator.Mask = 0;
- State->Decorrelator.Line = NULL;
- State->DecoTap[0] = 0;
- State->DecoTap[1] = 0;
- State->DecoTap[2] = 0;
+ state->Decorrelator.Mask = 0;
+ state->Decorrelator.Line = NULL;
+ state->DecoTap[0] = 0;
+ state->DecoTap[1] = 0;
+ state->DecoTap[2] = 0;
- State->Late.Gain = 0.0f;
- State->Late.DensityGain = 0.0f;
- State->Late.ApFeedCoeff = 0.0f;
- State->Late.MixCoeff = 0.0f;
+ state->Late.Gain = 0.0f;
+ state->Late.DensityGain = 0.0f;
+ state->Late.ApFeedCoeff = 0.0f;
+ state->Late.MixCoeff = 0.0f;
for(index = 0;index < 4;index++)
{
- State->Late.ApCoeff[index] = 0.0f;
- State->Late.ApDelay[index].Mask = 0;
- State->Late.ApDelay[index].Line = NULL;
- State->Late.ApOffset[index] = 0;
-
- State->Late.Coeff[index] = 0.0f;
- State->Late.Delay[index].Mask = 0;
- State->Late.Delay[index].Line = NULL;
- State->Late.Offset[index] = 0;
-
- State->Late.LpCoeff[index] = 0.0f;
- State->Late.LpSample[index] = 0.0f;
+ state->Late.ApCoeff[index] = 0.0f;
+ state->Late.ApDelay[index].Mask = 0;
+ state->Late.ApDelay[index].Line = NULL;
+ state->Late.ApOffset[index] = 0;
+
+ state->Late.Coeff[index] = 0.0f;
+ state->Late.Delay[index].Mask = 0;
+ state->Late.Delay[index].Line = NULL;
+ state->Late.Offset[index] = 0;
+
+ state->Late.LpCoeff[index] = 0.0f;
+ state->Late.LpSample[index] = 0.0f;
}
for(index = 0;index < MaxChannels;index++)
{
- State->Early.PanGain[index] = 0.0f;
- State->Late.PanGain[index] = 0.0f;
+ state->Early.PanGain[index] = 0.0f;
+ state->Late.PanGain[index] = 0.0f;
+ }
+
+ state->Echo.DensityGain = 0.0f;
+ state->Echo.Delay.Mask = 0;
+ state->Echo.Delay.Line = NULL;
+ state->Echo.ApDelay.Mask = 0;
+ state->Echo.ApDelay.Line = NULL;
+ state->Echo.Coeff = 0.0f;
+ state->Echo.ApFeedCoeff = 0.0f;
+ state->Echo.ApCoeff = 0.0f;
+ state->Echo.Offset = 0;
+ state->Echo.ApOffset = 0;
+ state->Echo.LpCoeff = 0.0f;
+ state->Echo.LpSample = 0.0f;
+ state->Echo.MixCoeff[0] = 0.0f;
+ state->Echo.MixCoeff[1] = 0.0f;
+
+ state->Offset = 0;
+
+ state->Gain = state->Late.PanGain;
+
+ return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory);
+
+ALeffectStateFactory *ALreverbStateFactory_getFactory(void)
+{
+ static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } };
+
+ return STATIC_CAST(ALeffectStateFactory, &ReverbFactory);
+}
+
+
+void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayHFLimit = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALeaxreverb_setParami(effect, context, param, vals[0]);
+}
+void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Density = val;
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Diffusion = val;
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Gain = val;
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.GainHF = val;
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.GainLF = val;
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayTime = val;
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayHFRatio = val;
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayLFRatio = val;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ReflectionsGain = val;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ReflectionsDelay = val;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.LateReverbGain = val;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.LateReverbDelay = val;
+ break;
+
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.AirAbsorptionGainHF = val;
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.EchoTime = val;
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.EchoDepth = val;
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ModulationTime = val;
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ModulationDepth = val;
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.HFReference = val;
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.LFReference = val;
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.RoomRolloffFactor = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_REFLECTIONS_PAN:
+ if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ LockContext(context);
+ props->Reverb.ReflectionsPan[0] = vals[0];
+ props->Reverb.ReflectionsPan[1] = vals[1];
+ props->Reverb.ReflectionsPan[2] = vals[2];
+ UnlockContext(context);
+ break;
+ case AL_EAXREVERB_LATE_REVERB_PAN:
+ if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ LockContext(context);
+ props->Reverb.LateReverbPan[0] = vals[0];
+ props->Reverb.LateReverbPan[1] = vals[1];
+ props->Reverb.LateReverbPan[2] = vals[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ ALeaxreverb_setParamf(effect, context, param, vals[0]);
+ break;
+ }
+}
+
+void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ *val = props->Reverb.DecayHFLimit;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALeaxreverb_getParami(effect, context, param, vals);
+}
+void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ *val = props->Reverb.Density;
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ *val = props->Reverb.Diffusion;
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ *val = props->Reverb.Gain;
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ *val = props->Reverb.GainHF;
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ *val = props->Reverb.GainLF;
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ *val = props->Reverb.DecayTime;
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ *val = props->Reverb.DecayHFRatio;
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ *val = props->Reverb.DecayLFRatio;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ *val = props->Reverb.ReflectionsGain;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ *val = props->Reverb.ReflectionsDelay;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ *val = props->Reverb.LateReverbGain;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ *val = props->Reverb.LateReverbDelay;
+ break;
+
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ *val = props->Reverb.AirAbsorptionGainHF;
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ *val = props->Reverb.EchoTime;
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ *val = props->Reverb.EchoDepth;
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ *val = props->Reverb.ModulationTime;
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ *val = props->Reverb.ModulationDepth;
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ *val = props->Reverb.HFReference;
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ *val = props->Reverb.LFReference;
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ *val = props->Reverb.RoomRolloffFactor;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_EAXREVERB_REFLECTIONS_PAN:
+ LockContext(context);
+ vals[0] = props->Reverb.ReflectionsPan[0];
+ vals[1] = props->Reverb.ReflectionsPan[1];
+ vals[2] = props->Reverb.ReflectionsPan[2];
+ UnlockContext(context);
+ break;
+ case AL_EAXREVERB_LATE_REVERB_PAN:
+ LockContext(context);
+ vals[0] = props->Reverb.LateReverbPan[0];
+ vals[1] = props->Reverb.LateReverbPan[1];
+ vals[2] = props->Reverb.LateReverbPan[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ ALeaxreverb_getParamf(effect, context, param, vals);
+ break;
+ }
+}
+
+DEFINE_ALEFFECT_VTABLE(ALeaxreverb);
+
+void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayHFLimit = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
+}
+void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+ ALreverb_setParami(effect, context, param, vals[0]);
+}
+void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+ ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Density = val;
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Diffusion = val;
+ break;
+
+ case AL_REVERB_GAIN:
+ if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.Gain = val;
+ break;
+
+ case AL_REVERB_GAINHF:
+ if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.GainHF = val;
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayTime = val;
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.DecayHFRatio = val;
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ReflectionsGain = val;
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.ReflectionsDelay = val;
+ break;
+
+ case AL_REVERB_LATE_REVERB_GAIN:
+ if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.LateReverbGain = val;
+ break;
+
+ case AL_REVERB_LATE_REVERB_DELAY:
+ if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.LateReverbDelay = val;
+ break;
+
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.AirAbsorptionGainHF = val;
+ break;
+
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ props->Reverb.RoomRolloffFactor = val;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{
+ ALreverb_setParamf(effect, context, param, vals[0]);
+}
+
+void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ *val = props->Reverb.DecayHFLimit;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+ ALreverb_getParami(effect, context, param, vals);
+}
+void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+ const ALeffectProps *props = &effect->Props;
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ *val = props->Reverb.Density;
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ *val = props->Reverb.Diffusion;
+ break;
+
+ case AL_REVERB_GAIN:
+ *val = props->Reverb.Gain;
+ break;
+
+ case AL_REVERB_GAINHF:
+ *val = props->Reverb.GainHF;
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ *val = props->Reverb.DecayTime;
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ *val = props->Reverb.DecayHFRatio;
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ *val = props->Reverb.ReflectionsGain;
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ *val = props->Reverb.ReflectionsDelay;
+ break;
- State->Echo.DensityGain = 0.0f;
- State->Echo.Delay.Mask = 0;
- State->Echo.Delay.Line = NULL;
- State->Echo.ApDelay.Mask = 0;
- State->Echo.ApDelay.Line = NULL;
- State->Echo.Coeff = 0.0f;
- State->Echo.ApFeedCoeff = 0.0f;
- State->Echo.ApCoeff = 0.0f;
- State->Echo.Offset = 0;
- State->Echo.ApOffset = 0;
- State->Echo.LpCoeff = 0.0f;
- State->Echo.LpSample = 0.0f;
- State->Echo.MixCoeff[0] = 0.0f;
- State->Echo.MixCoeff[1] = 0.0f;
-
- State->Offset = 0;
-
- State->Gain = State->Late.PanGain;
-
- return &State->state;
+ case AL_REVERB_LATE_REVERB_GAIN:
+ *val = props->Reverb.LateReverbGain;
+ break;
+
+ case AL_REVERB_LATE_REVERB_DELAY:
+ *val = props->Reverb.LateReverbDelay;
+ break;
+
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ *val = props->Reverb.AirAbsorptionGainHF;
+ break;
+
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ *val = props->Reverb.RoomRolloffFactor;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{
+ ALreverb_getParamf(effect, context, param, vals);
}
+
+DEFINE_ALEFFECT_VTABLE(ALreverb);
diff --git a/Alc/evtqueue.h b/Alc/evtqueue.h
new file mode 100644
index 00000000..95702d79
--- /dev/null
+++ b/Alc/evtqueue.h
@@ -0,0 +1,31 @@
+#ifndef AL_EVTQUEUE_H
+#define AL_EVTQUEUE_H
+
+#include "AL/al.h"
+
+#include "alMain.h"
+
+typedef struct MidiEvent {
+ ALuint64 time;
+ ALuint event;
+ union {
+ ALuint val[2];
+ struct {
+ ALvoid *data;
+ ALsizei size;
+ } sysex;
+ } param;
+} MidiEvent;
+
+typedef struct EvtQueue {
+ MidiEvent *events;
+ ALsizei pos;
+ ALsizei size;
+ ALsizei maxsize;
+} EvtQueue;
+
+void InitEvtQueue(EvtQueue *queue);
+void ResetEvtQueue(EvtQueue *queue);
+ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt);
+
+#endif /* AL_EVTQUEUE_H */
diff --git a/Alc/helpers.c b/Alc/helpers.c
index 6358f044..f8a5f13b 100644
--- a/Alc/helpers.c
+++ b/Alc/helpers.c
@@ -28,6 +28,7 @@
#include <malloc.h>
#endif
+#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
#define INITGUID
#include <windows.h>
@@ -52,12 +53,17 @@ DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xa
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
#endif
#endif
+#endif /* AL_NO_UID_DEFS */
+
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#ifdef HAVE_CPUID_H
#include <cpuid.h>
#endif
+#ifdef HAVE_SYS_SYSCONF_H
+#include <sys/sysconf.h>
+#endif
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
@@ -66,6 +72,27 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
#endif
#include "alMain.h"
+#include "atomic.h"
+#include "uintmap.h"
+#include "compat.h"
+
+
+extern inline RefCount IncrementRef(volatile RefCount *ptr);
+extern inline RefCount DecrementRef(volatile RefCount *ptr);
+extern inline int ExchangeInt(volatile int *ptr, int newval);
+extern inline void *ExchangePtr(XchgPtr *ptr, void *newval);
+extern inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval);
+extern inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval);
+
+extern inline void LockUIntMapRead(UIntMap *map);
+extern inline void UnlockUIntMapRead(UIntMap *map);
+extern inline void LockUIntMapWrite(UIntMap *map);
+extern inline void UnlockUIntMapWrite(UIntMap *map);
+
+extern inline ALuint NextPowerOf2(ALuint value);
+extern inline ALint fastf2i(ALfloat f);
+extern inline ALuint fastf2u(ALfloat f);
+
ALuint CPUCapFlags = 0;
@@ -104,10 +131,12 @@ void FillCPUCaps(ALuint capfilter)
if(maxfunc >= 1 &&
__get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
{
-#ifdef bit_SSE
- if((cpuinf[0].regs[3]&bit_SSE))
+ if((cpuinf[0].regs[3]&(1<<25)))
+ {
caps |= CPU_CAP_SSE;
-#endif
+ if((cpuinf[0].regs[3]&(1<<26)))
+ caps |= CPU_CAP_SSE2;
+ }
}
}
#elif defined(HAVE_WINDOWS_H)
@@ -119,7 +148,11 @@ void FillCPUCaps(ALuint capfilter)
else
{
if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
+ {
caps |= CPU_CAP_SSE;
+ if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
+ caps |= CPU_CAP_SSE2;
+ }
}
#endif
#ifdef HAVE_NEON
@@ -127,9 +160,10 @@ void FillCPUCaps(ALuint capfilter)
caps |= CPU_CAP_NEON;
#endif
- TRACE("Got caps:%s%s%s\n", ((caps&CPU_CAP_SSE)?((capfilter&CPU_CAP_SSE)?" SSE":" (SSE)"):""),
- ((caps&CPU_CAP_NEON)?((capfilter&CPU_CAP_NEON)?" Neon":" (Neon)"):""),
- ((!caps)?" -none-":""));
+ TRACE("Got caps:%s%s%s%s\n", ((caps&CPU_CAP_SSE)?((capfilter&CPU_CAP_SSE)?" SSE":" (SSE)"):""),
+ ((caps&CPU_CAP_SSE2)?((capfilter&CPU_CAP_SSE2)?" SSE2":" (SSE2)"):""),
+ ((caps&CPU_CAP_NEON)?((capfilter&CPU_CAP_NEON)?" Neon":" (Neon)"):""),
+ ((!caps)?" -none-":""));
CPUCapFlags = caps & capfilter;
}
@@ -192,25 +226,30 @@ void al_free(void *ptr)
void SetMixerFPUMode(FPUCtl *ctl)
{
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
- unsigned short fpuState;
- __asm__ __volatile__("fnstcw %0" : "=m" (*&fpuState));
- ctl->state = fpuState;
- fpuState &= ~0x300; /* clear precision to single */
- fpuState |= 0xC00; /* set round-to-zero */
- __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState));
-#ifdef HAVE_SSE
+#ifdef HAVE_FENV_H
+ fegetenv(STATIC_CAST(fenv_t, ctl));
+#if defined(__GNUC__) && defined(HAVE_SSE)
+ if((CPUCapFlags&CPU_CAP_SSE))
+ __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
+#endif
+
+#ifdef FE_TOWARDZERO
+ fesetround(FE_TOWARDZERO);
+#endif
+#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
{
- int sseState;
- __asm__ __volatile__("stmxcsr %0" : "=m" (*&sseState));
- ctl->sse_state = sseState;
- sseState |= 0x0C00; /* set round-to-zero */
+ int sseState = ctl->sse_state;
+ sseState |= 0x6000; /* set round-to-zero */
sseState |= 0x8000; /* set flush-to-zero */
+ if((CPUCapFlags&CPU_CAP_SSE2))
+ sseState |= 0x0040; /* set denormals-are-zero */
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState));
}
#endif
+
#elif defined(HAVE___CONTROL87_2)
+
int mode;
__control87_2(0, 0, &ctl->state, NULL);
__control87_2(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC, &mode, NULL);
@@ -221,54 +260,54 @@ void SetMixerFPUMode(FPUCtl *ctl)
__control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode);
}
#endif
+
#elif defined(HAVE__CONTROLFP)
+
ctl->state = _controlfp(0, 0);
(void)_controlfp(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC);
-#elif defined(HAVE_FESETROUND)
- ctl->state = fegetround();
-#ifdef FE_TOWARDZERO
- fesetround(FE_TOWARDZERO);
-#endif
#endif
}
void RestoreFPUMode(const FPUCtl *ctl)
{
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
- unsigned short fpuState = ctl->state;
- __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState));
-#ifdef HAVE_SSE
+#ifdef HAVE_FENV_H
+ fesetenv(STATIC_CAST(fenv_t, ctl));
+#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
#endif
+
#elif defined(HAVE___CONTROL87_2)
+
int mode;
__control87_2(ctl->state, _MCW_RC|_MCW_PC, &mode, NULL);
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
__control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode);
#endif
+
#elif defined(HAVE__CONTROLFP)
+
_controlfp(ctl->state, _MCW_RC|_MCW_PC);
-#elif defined(HAVE_FESETROUND)
- fesetround(ctl->state);
#endif
}
#ifdef _WIN32
-void pthread_once(pthread_once_t *once, void (*callback)(void))
+extern inline int alsched_yield(void);
+
+void althread_once(althread_once_t *once, void (*callback)(void))
{
LONG ret;
while((ret=InterlockedExchange(once, 1)) == 1)
- sched_yield();
+ alsched_yield();
if(ret == 0)
callback();
InterlockedExchange(once, 2);
}
-int pthread_key_create(pthread_key_t *key, void (*callback)(void*))
+int althread_key_create(althread_key_t *key, void (*callback)(void*))
{
*key = TlsAlloc();
if(callback)
@@ -276,17 +315,17 @@ int pthread_key_create(pthread_key_t *key, void (*callback)(void*))
return 0;
}
-int pthread_key_delete(pthread_key_t key)
+int althread_key_delete(althread_key_t key)
{
InsertUIntMapEntry(&TlsDestructor, key, NULL);
TlsFree(key);
return 0;
}
-void *pthread_getspecific(pthread_key_t key)
+void *althread_getspecific(althread_key_t key)
{ return TlsGetValue(key); }
-int pthread_setspecific(pthread_key_t key, void *val)
+int althread_setspecific(althread_key_t key, void *val)
{
TlsSetValue(key, val);
return 0;
@@ -330,6 +369,8 @@ WCHAR *strdupW(const WCHAR *str)
#include <pthread_np.h>
#endif
#include <sched.h>
+#include <time.h>
+#include <sys/time.h>
void InitializeCriticalSection(CRITICAL_SECTION *cs)
{
@@ -449,20 +490,13 @@ void *GetSymbol(void *handle, const char *name)
void al_print(const char *type, const char *func, const char *fmt, ...)
{
- char str[256];
- int i;
+ va_list ap;
- i = snprintf(str, sizeof(str), "AL lib: %s %s: ", type, func);
- if(i > 0 && (unsigned int)i < sizeof(str))
- {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(str+i, sizeof(str)-i, fmt, ap);
- va_end(ap);
- }
- str[sizeof(str)-1] = 0;
+ va_start(ap, fmt);
+ fprintf(LogFile, "AL lib: %s %s: ", type, func);
+ vfprintf(LogFile, fmt, ap);
+ va_end(ap);
- fprintf(LogFile, "%s", str);
fflush(LogFile);
}
@@ -495,7 +529,7 @@ void SetRTPriority(void)
static void Lock(volatile ALenum *l)
{
while(ExchangeInt(l, AL_TRUE) == AL_TRUE)
- sched_yield();
+ alsched_yield();
}
static void Unlock(volatile ALenum *l)
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index 11922cc7..49bb97a3 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -92,7 +92,7 @@ static void CalcEvIndices(const struct Hrtf *Hrtf, ALfloat ev, ALuint *evidx, AL
*/
static void CalcAzIndices(const struct Hrtf *Hrtf, ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu)
{
- az = (F_PI*2.0f + az) * Hrtf->azCount[evidx] / (F_PI*2.0f);
+ az = (F_2PI + az) * Hrtf->azCount[evidx] / (F_2PI);
azidx[0] = fastf2u(az) % Hrtf->azCount[evidx];
azidx[1] = (azidx[0] + 1) % Hrtf->azCount[evidx];
*azmu = az - floorf(az);
@@ -783,6 +783,30 @@ const struct Hrtf *GetHrtf(ALCdevice *device)
return NULL;
}
+void FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate)
+{
+ const struct Hrtf *hrtf = &DefaultHrtf;
+
+ if(device->Frequency != DefaultHrtf.sampleRate)
+ {
+ hrtf = LoadedHrtfs;
+ while(hrtf != NULL)
+ {
+ if(device->Frequency == hrtf->sampleRate)
+ break;
+ hrtf = hrtf->next;
+ }
+
+ if(hrtf == NULL)
+ hrtf = LoadHrtf(device->Frequency);
+ if(hrtf == NULL)
+ hrtf = &DefaultHrtf;
+ }
+
+ *chans = DevFmtStereo;
+ *srate = hrtf->sampleRate;
+}
+
void FreeHrtfs(void)
{
struct Hrtf *Hrtf = NULL;
diff --git a/Alc/midi/base.c b/Alc/midi/base.c
new file mode 100644
index 00000000..25dd19d9
--- /dev/null
+++ b/Alc/midi/base.c
@@ -0,0 +1,278 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "midi/base.h"
+
+#include "alMidi.h"
+#include "alMain.h"
+#include "alError.h"
+#include "alThunk.h"
+#include "evtqueue.h"
+#include "rwlock.h"
+#include "alu.h"
+
+
+/* Microsecond resolution */
+#define TICKS_PER_SECOND (1000000)
+
+/* MIDI events */
+#define SYSEX_EVENT (0xF0)
+
+
+void InitEvtQueue(EvtQueue *queue)
+{
+ queue->events = NULL;
+ queue->maxsize = 0;
+ queue->size = 0;
+ queue->pos = 0;
+}
+
+void ResetEvtQueue(EvtQueue *queue)
+{
+ ALsizei i;
+ for(i = 0;i < queue->size;i++)
+ {
+ if(queue->events[i].event == SYSEX_EVENT)
+ {
+ free(queue->events[i].param.sysex.data);
+ queue->events[i].param.sysex.data = NULL;
+ }
+ }
+
+ free(queue->events);
+ queue->events = NULL;
+ queue->maxsize = 0;
+ queue->size = 0;
+ queue->pos = 0;
+}
+
+ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt)
+{
+ ALsizei pos;
+
+ if(queue->maxsize == queue->size)
+ {
+ if(queue->pos > 0)
+ {
+ /* Queue has some stale entries, remove them to make space for more
+ * events. */
+ for(pos = 0;pos < queue->pos;pos++)
+ {
+ if(queue->events[pos].event == SYSEX_EVENT)
+ {
+ free(queue->events[pos].param.sysex.data);
+ queue->events[pos].param.sysex.data = NULL;
+ }
+ }
+ memmove(&queue->events[0], &queue->events[queue->pos],
+ (queue->size-queue->pos)*sizeof(queue->events[0]));
+ queue->size -= queue->pos;
+ queue->pos = 0;
+ }
+ else
+ {
+ /* Queue is full, double the allocated space. */
+ void *temp = NULL;
+ ALsizei newsize;
+
+ newsize = (queue->maxsize ? (queue->maxsize<<1) : 16);
+ if(newsize > queue->maxsize)
+ temp = realloc(queue->events, newsize * sizeof(queue->events[0]));
+ if(!temp)
+ return AL_OUT_OF_MEMORY;
+
+ queue->events = temp;
+ queue->maxsize = newsize;
+ }
+ }
+
+ pos = queue->pos;
+ if(queue->size > 0)
+ {
+ ALsizei high = queue->size - 1;
+ while(pos < high)
+ {
+ ALsizei mid = pos + (high-pos)/2;
+ if(queue->events[mid].time < evt->time)
+ pos = mid + 1;
+ else
+ high = mid;
+ }
+ while(pos < queue->size && queue->events[pos].time <= evt->time)
+ pos++;
+
+ if(pos < queue->size)
+ memmove(&queue->events[pos+1], &queue->events[pos],
+ (queue->size-pos)*sizeof(queue->events[0]));
+ }
+
+ queue->events[pos] = *evt;
+ queue->size++;
+
+ return AL_NO_ERROR;
+}
+
+
+void MidiSynth_Construct(MidiSynth *self, ALCdevice *device)
+{
+ InitEvtQueue(&self->EventQueue);
+
+ RWLockInit(&self->Lock);
+
+ self->Soundfonts = NULL;
+ self->NumSoundfonts = 0;
+
+ self->Gain = 1.0f;
+ self->State = AL_INITIAL;
+
+ self->LastEvtTime = 0;
+ self->NextEvtTime = UINT64_MAX;
+ self->SamplesSinceLast = 0.0;
+ self->SamplesToNext = 0.0;
+
+ self->SamplesPerTick = (ALdouble)device->Frequency / TICKS_PER_SECOND;
+}
+
+void MidiSynth_Destruct(MidiSynth *self)
+{
+ ALsizei i;
+
+ for(i = 0;i < self->NumSoundfonts;i++)
+ DecrementRef(&self->Soundfonts[i]->ref);
+ free(self->Soundfonts);
+ self->Soundfonts = NULL;
+ self->NumSoundfonts = 0;
+
+ ResetEvtQueue(&self->EventQueue);
+}
+
+
+ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
+{
+ ALCdevice *device = context->Device;
+ ALsoundfont **sfonts;
+ ALsizei i;
+
+ if(self->State != AL_INITIAL && self->State != AL_STOPPED)
+ return AL_INVALID_OPERATION;
+
+ sfonts = calloc(1, count * sizeof(sfonts[0]));
+ if(!sfonts) return AL_OUT_OF_MEMORY;
+
+ for(i = 0;i < count;i++)
+ {
+ if(ids[i] == 0)
+ sfonts[i] = ALsoundfont_getDefSoundfont(context);
+ else if(!(sfonts[i]=LookupSfont(device, ids[i])))
+ {
+ free(sfonts);
+ return AL_INVALID_VALUE;
+ }
+ }
+
+ for(i = 0;i < count;i++)
+ IncrementRef(&sfonts[i]->ref);
+ sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts);
+ count = ExchangeInt(&self->NumSoundfonts, count);
+
+ for(i = 0;i < count;i++)
+ DecrementRef(&sfonts[i]->ref);
+ free(sfonts);
+
+ return AL_NO_ERROR;
+}
+
+extern inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain);
+extern inline ALfloat MidiSynth_getGain(const MidiSynth *self);
+extern inline void MidiSynth_setState(MidiSynth *self, ALenum state);
+extern inline ALenum MidiSynth_getState(const MidiSynth *self);
+
+void MidiSynth_stop(MidiSynth *self)
+{
+ ResetEvtQueue(&self->EventQueue);
+
+ self->LastEvtTime = 0;
+ self->NextEvtTime = UINT64_MAX;
+ self->SamplesSinceLast = 0.0;
+ self->SamplesToNext = 0.0;
+}
+
+extern inline void MidiSynth_reset(MidiSynth *self);
+
+ALuint64 MidiSynth_getTime(const MidiSynth *self)
+{
+ ALuint64 time = self->LastEvtTime + (self->SamplesSinceLast/self->SamplesPerTick);
+ return clampu64(time, self->LastEvtTime, self->NextEvtTime);
+}
+
+extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self);
+
+void MidiSynth_setSampleRate(MidiSynth *self, ALdouble srate)
+{
+ ALdouble sampletickrate = srate / TICKS_PER_SECOND;
+
+ self->SamplesSinceLast = self->SamplesSinceLast * sampletickrate / self->SamplesPerTick;
+ self->SamplesToNext = self->SamplesToNext * sampletickrate / self->SamplesPerTick;
+ self->SamplesPerTick = sampletickrate;
+}
+
+extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device);
+
+ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2)
+{
+ MidiEvent entry;
+ ALenum err;
+
+ entry.time = time;
+ entry.event = event;
+ entry.param.val[0] = param1;
+ entry.param.val[1] = param2;
+
+ err = InsertEvtQueue(&self->EventQueue, &entry);
+ if(err != AL_NO_ERROR) return err;
+
+ if(entry.time < self->NextEvtTime)
+ {
+ self->NextEvtTime = entry.time;
+
+ self->SamplesToNext = (self->NextEvtTime - self->LastEvtTime) * self->SamplesPerTick;
+ self->SamplesToNext -= self->SamplesSinceLast;
+ }
+
+ return AL_NO_ERROR;
+}
+
+ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size)
+{
+ MidiEvent entry;
+ ALenum err;
+
+ entry.time = time;
+ entry.event = SYSEX_EVENT;
+ entry.param.sysex.size = size;
+ entry.param.sysex.data = malloc(size);
+ if(!entry.param.sysex.data)
+ return AL_OUT_OF_MEMORY;
+ memcpy(entry.param.sysex.data, data, size);
+
+ err = InsertEvtQueue(&self->EventQueue, &entry);
+ if(err != AL_NO_ERROR)
+ {
+ free(entry.param.sysex.data);
+ return err;
+ }
+
+ if(entry.time < self->NextEvtTime)
+ {
+ self->NextEvtTime = entry.time;
+
+ self->SamplesToNext = (self->NextEvtTime - self->LastEvtTime) * self->SamplesPerTick;
+ self->SamplesToNext -= self->SamplesSinceLast;
+ }
+
+ return AL_NO_ERROR;
+}
diff --git a/Alc/midi/base.h b/Alc/midi/base.h
new file mode 100644
index 00000000..f900c941
--- /dev/null
+++ b/Alc/midi/base.h
@@ -0,0 +1,128 @@
+#ifndef AL_MIDI_BASE_H
+#define AL_MIDI_BASE_H
+
+#include "alMain.h"
+#include "atomic.h"
+#include "evtqueue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ALsoundfont;
+
+typedef size_t (*ReaderCb)(void *ptr, size_t size, void *stream);
+typedef struct Reader {
+ ReaderCb cb;
+ void *ptr;
+ int error;
+} Reader;
+#define READ(x_, buf_, len_) ((x_)->cb((buf_), (len_), (x_)->ptr))
+#define READERR(x_) ((x_)->error)
+
+ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context);
+
+
+struct MidiSynthVtable;
+
+typedef struct MidiSynth {
+ EvtQueue EventQueue;
+
+ ALuint64 LastEvtTime;
+ ALuint64 NextEvtTime;
+ ALdouble SamplesSinceLast;
+ ALdouble SamplesToNext;
+
+ ALdouble SamplesPerTick;
+
+ /* NOTE: This rwlock is for the state and soundfont. The EventQueue and
+ * related must instead use the device lock as they're used in the mixer
+ * thread.
+ */
+ RWLock Lock;
+
+ struct ALsoundfont **Soundfonts;
+ ALsizei NumSoundfonts;
+
+ volatile ALfloat Gain;
+ volatile ALenum State;
+
+ const struct MidiSynthVtable *vtbl;
+} MidiSynth;
+
+void MidiSynth_Construct(MidiSynth *self, ALCdevice *device);
+void MidiSynth_Destruct(MidiSynth *self);
+ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
+inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; }
+inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; }
+inline void MidiSynth_setState(MidiSynth *self, ALenum state) { ExchangeInt(&self->State, state); }
+inline ALenum MidiSynth_getState(const MidiSynth *self) { return self->State; }
+void MidiSynth_stop(MidiSynth *self);
+inline void MidiSynth_reset(MidiSynth *self) { MidiSynth_stop(self); }
+ALuint64 MidiSynth_getTime(const MidiSynth *self);
+inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self)
+{
+ if(self->EventQueue.pos == self->EventQueue.size)
+ return UINT64_MAX;
+ return self->EventQueue.events[self->EventQueue.pos].time;
+}
+void MidiSynth_setSampleRate(MidiSynth *self, ALdouble srate);
+inline void MidiSynth_update(MidiSynth *self, ALCdevice *device)
+{ MidiSynth_setSampleRate(self, device->Frequency); }
+ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2);
+ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size);
+
+
+struct MidiSynthVtable {
+ void (*const Destruct)(MidiSynth *self);
+
+ ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
+
+ void (*const setGain)(MidiSynth *self, ALfloat gain);
+ void (*const setState)(MidiSynth *self, ALenum state);
+
+ void (*const stop)(MidiSynth *self);
+ void (*const reset)(MidiSynth *self);
+
+ void (*const update)(MidiSynth *self, ALCdevice *device);
+ void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
+
+ void (*const Delete)(MidiSynth *self);
+};
+
+#define DEFINE_MIDISYNTH_VTABLE(T) \
+DECLARE_THUNK(T, MidiSynth, void, Destruct) \
+DECLARE_THUNK3(T, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) \
+DECLARE_THUNK1(T, MidiSynth, void, setGain, ALfloat) \
+DECLARE_THUNK1(T, MidiSynth, void, setState, ALenum) \
+DECLARE_THUNK(T, MidiSynth, void, stop) \
+DECLARE_THUNK(T, MidiSynth, void, reset) \
+DECLARE_THUNK1(T, MidiSynth, void, update, ALCdevice*) \
+DECLARE_THUNK2(T, MidiSynth, void, process, ALuint, ALfloatBUFFERSIZE*restrict) \
+DECLARE_THUNK(T, MidiSynth, void, Delete) \
+ \
+static const struct MidiSynthVtable T##_MidiSynth_vtable = { \
+ T##_MidiSynth_Destruct, \
+ \
+ T##_MidiSynth_selectSoundfonts, \
+ T##_MidiSynth_setGain, \
+ T##_MidiSynth_setState, \
+ T##_MidiSynth_stop, \
+ T##_MidiSynth_reset, \
+ T##_MidiSynth_update, \
+ T##_MidiSynth_process, \
+ \
+ T##_MidiSynth_Delete, \
+}
+
+
+MidiSynth *FSynth_create(ALCdevice *device);
+MidiSynth *DSynth_create(ALCdevice *device);
+
+MidiSynth *SynthCreate(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AL_MIDI_BASE_H */
diff --git a/Alc/midi/dummy.c b/Alc/midi/dummy.c
new file mode 100644
index 00000000..71c03efb
--- /dev/null
+++ b/Alc/midi/dummy.c
@@ -0,0 +1,95 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "alMain.h"
+#include "alError.h"
+#include "evtqueue.h"
+#include "rwlock.h"
+#include "alu.h"
+
+#include "midi/base.h"
+
+typedef struct DSynth {
+ DERIVE_FROM_TYPE(MidiSynth);
+} DSynth;
+
+static void DSynth_Construct(DSynth *self, ALCdevice *device);
+static DECLARE_FORWARD(DSynth, MidiSynth, void, Destruct)
+static DECLARE_FORWARD3(DSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*)
+static DECLARE_FORWARD1(DSynth, MidiSynth, void, setGain, ALfloat)
+static DECLARE_FORWARD1(DSynth, MidiSynth, void, setState, ALenum)
+static DECLARE_FORWARD(DSynth, MidiSynth, void, stop)
+static DECLARE_FORWARD(DSynth, MidiSynth, void, reset)
+static DECLARE_FORWARD1(DSynth, MidiSynth, void, update, ALCdevice*)
+static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
+static void DSynth_Delete(DSynth *self);
+DEFINE_MIDISYNTH_VTABLE(DSynth);
+
+
+static void DSynth_Construct(DSynth *self, ALCdevice *device)
+{
+ MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
+ SET_VTABLE2(DSynth, MidiSynth, self);
+}
+
+
+static void DSynth_processQueue(DSynth *self, ALuint64 time)
+{
+ EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
+
+ while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
+ queue->pos++;
+}
+
+static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloatBUFFERSIZE*restrict UNUSED(DryBuffer))
+{
+ MidiSynth *synth = STATIC_CAST(MidiSynth, self);
+
+ if(synth->State != AL_PLAYING)
+ return;
+
+ synth->SamplesSinceLast += SamplesToDo;
+ synth->SamplesToNext -= SamplesToDo;
+ while(synth->SamplesToNext < 1.0f)
+ {
+ ALuint64 time = synth->NextEvtTime;
+ if(time == UINT64_MAX)
+ {
+ synth->SamplesToNext = 0.0;
+ break;
+ }
+
+ synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
+ synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
+ synth->LastEvtTime = time;
+ DSynth_processQueue(self, time);
+
+ synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
+ if(synth->NextEvtTime != UINT64_MAX)
+ synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
+ }
+}
+
+
+static void DSynth_Delete(DSynth *self)
+{
+ free(self);
+}
+
+
+MidiSynth *DSynth_create(ALCdevice *device)
+{
+ DSynth *synth = calloc(1, sizeof(*synth));
+ if(!synth)
+ {
+ ERR("Failed to allocate DSynth\n");
+ return NULL;
+ }
+ DSynth_Construct(synth, device);
+ return STATIC_CAST(MidiSynth, synth);
+}
diff --git a/Alc/midi/fluidsynth.c b/Alc/midi/fluidsynth.c
new file mode 100644
index 00000000..9d58f87b
--- /dev/null
+++ b/Alc/midi/fluidsynth.c
@@ -0,0 +1,843 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "midi/base.h"
+
+#include "alMain.h"
+#include "alError.h"
+#include "alMidi.h"
+#include "evtqueue.h"
+#include "rwlock.h"
+#include "alu.h"
+
+#ifdef HAVE_FLUIDSYNTH
+
+#include <fluidsynth.h>
+
+
+/* MIDI events */
+#define SYSEX_EVENT (0xF0)
+
+/* MIDI controllers */
+#define CTRL_BANKSELECT_MSB (0)
+#define CTRL_BANKSELECT_LSB (32)
+#define CTRL_ALLNOTESOFF (123)
+
+
+static int getGenInput(ALenum input)
+{
+ switch(input)
+ {
+ case AL_ONE_SOFT: return FLUID_MOD_NONE;
+ case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY;
+ case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY;
+ case AL_KEYPRESSURE_SOFT: return FLUID_MOD_KEYPRESSURE;
+ case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE;
+ case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL;
+ case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS;
+ }
+ return input&0x7F;
+}
+
+static int getGenFlags(ALenum input, ALenum type, ALenum form)
+{
+ int ret = 0;
+
+ switch(type)
+ {
+ case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break;
+ case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break;
+ case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break;
+ case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break;
+ }
+ switch(form)
+ {
+ case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break;
+ case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break;
+ case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break;
+ case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break;
+ }
+ /* Source input values less than 128 correspond to a MIDI continuous
+ * controller. Otherwise, it's a general controller. */
+ if(input < 128) ret |= FLUID_MOD_CC;
+ else ret |= FLUID_MOD_GC;
+
+ return ret;
+}
+
+static enum fluid_gen_type getSf2Gen(ALenum gen)
+{
+ switch(gen)
+ {
+ case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH;
+ case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH;
+ case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH;
+ case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC;
+ case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ;
+ case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC;
+ case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC;
+ case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL;
+ case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND;
+ case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND;
+ case AL_PAN_SOFT: return GEN_PAN;
+ case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY;
+ case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ;
+ case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY;
+ case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ;
+ case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY;
+ case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK;
+ case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD;
+ case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY;
+ case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN;
+ case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE;
+ case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD;
+ case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY;
+ case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY;
+ case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK;
+ case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD;
+ case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY;
+ case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN;
+ case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE;
+ case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD;
+ case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY;
+ case AL_ATTENUATION_SOFT: return GEN_ATTENUATION;
+ case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE;
+ case AL_TUNING_FINE_SOFT: return GEN_FINETUNE;
+ case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE;
+ }
+ ERR("Unhandled generator: 0x%04x\n", gen);
+ return 0;
+}
+
+static int getSf2LoopMode(ALenum mode)
+{
+ switch(mode)
+ {
+ case AL_NONE: return 0;
+ case AL_LOOP_CONTINUOUS_SOFT: return 1;
+ case AL_LOOP_UNTIL_RELEASE_SOFT: return 3;
+ }
+ return 0;
+}
+
+static int getSampleType(ALenum type)
+{
+ switch(type)
+ {
+ case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO;
+ case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT;
+ case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT;
+ }
+ return FLUID_SAMPLETYPE_MONO;
+}
+
+typedef struct FSample {
+ DERIVE_FROM_TYPE(fluid_sample_t);
+
+ ALfontsound *Sound;
+
+ fluid_mod_t *Mods;
+ ALsizei NumMods;
+} FSample;
+
+static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sfont)
+{
+ fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
+ memset(sample->name, 0, sizeof(sample->name));
+ sample->start = sound->Start;
+ sample->end = sound->End;
+ sample->loopstart = sound->LoopStart;
+ sample->loopend = sound->LoopEnd;
+ sample->samplerate = sound->SampleRate;
+ sample->origpitch = sound->PitchKey;
+ sample->pitchadj = sound->PitchCorrection;
+ sample->sampletype = getSampleType(sound->SampleType);
+ sample->valid = 1;
+ sample->data = sfont->Samples;
+
+ sample->amplitude_that_reaches_noise_floor_is_valid = 0;
+ sample->amplitude_that_reaches_noise_floor = 0.0;
+
+ sample->refcount = 0;
+
+ sample->notify = NULL;
+
+ sample->userdata = self;
+
+ self->Sound = sound;
+
+ self->NumMods = 0;
+ self->Mods = calloc(sound->ModulatorMap.size, sizeof(self->Mods[0]));
+ if(self->Mods)
+ {
+ ALsizei i;
+
+ self->NumMods = sound->ModulatorMap.size;
+ for(i = 0;i < self->NumMods;i++)
+ {
+ ALsfmodulator *mod = sound->ModulatorMap.array[i].value;
+ fluid_mod_set_source1(&self->Mods[i], getGenInput(mod->Source[0].Input),
+ getGenFlags(mod->Source[0].Input, mod->Source[0].Type,
+ mod->Source[0].Form));
+ fluid_mod_set_source2(&self->Mods[i], getGenInput(mod->Source[1].Input),
+ getGenFlags(mod->Source[1].Input, mod->Source[1].Type,
+ mod->Source[1].Form));
+ fluid_mod_set_amount(&self->Mods[i], mod->Amount);
+ fluid_mod_set_dest(&self->Mods[i], getSf2Gen(mod->Dest));
+ self->Mods[i].next = NULL;
+ }
+ }
+}
+
+static void FSample_Destruct(FSample *self)
+{
+ free(self->Mods);
+ self->Mods = NULL;
+ self->NumMods = 0;
+}
+
+
+typedef struct FPreset {
+ DERIVE_FROM_TYPE(fluid_preset_t);
+
+ char Name[16];
+
+ int Preset;
+ int Bank;
+
+ FSample *Samples;
+ ALsizei NumSamples;
+} FPreset;
+
+static char* FPreset_getName(fluid_preset_t *preset);
+static int FPreset_getPreset(fluid_preset_t *preset);
+static int FPreset_getBank(fluid_preset_t *preset);
+static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity);
+
+static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent, ALsoundfont *sfont)
+{
+ STATIC_CAST(fluid_preset_t, self)->data = self;
+ STATIC_CAST(fluid_preset_t, self)->sfont = parent;
+ STATIC_CAST(fluid_preset_t, self)->free = NULL;
+ STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName;
+ STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank;
+ STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset;
+ STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn;
+ STATIC_CAST(fluid_preset_t, self)->notify = NULL;
+
+ memset(self->Name, 0, sizeof(self->Name));
+ self->Preset = preset->Preset;
+ self->Bank = preset->Bank;
+
+ self->NumSamples = 0;
+ self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0]));
+ if(self->Samples)
+ {
+ ALsizei i;
+ self->NumSamples = preset->NumSounds;
+ for(i = 0;i < self->NumSamples;i++)
+ FSample_Construct(&self->Samples[i], preset->Sounds[i], sfont);
+ }
+}
+
+static void FPreset_Destruct(FPreset *self)
+{
+ ALsizei i;
+
+ for(i = 0;i < self->NumSamples;i++)
+ FSample_Destruct(&self->Samples[i]);
+ free(self->Samples);
+ self->Samples = NULL;
+ self->NumSamples = 0;
+}
+
+static ALboolean FPreset_canDelete(FPreset *self)
+{
+ ALsizei i;
+
+ for(i = 0;i < self->NumSamples;i++)
+ {
+ if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0)
+ return AL_FALSE;
+ }
+ return AL_TRUE;
+}
+
+static char* FPreset_getName(fluid_preset_t *preset)
+{
+ return ((FPreset*)preset->data)->Name;
+}
+
+static int FPreset_getPreset(fluid_preset_t *preset)
+{
+ return ((FPreset*)preset->data)->Preset;
+}
+
+static int FPreset_getBank(fluid_preset_t *preset)
+{
+ return ((FPreset*)preset->data)->Bank;
+}
+
+static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel)
+{
+ FPreset *self = ((FPreset*)preset->data);
+ ALsizei i;
+
+ for(i = 0;i < self->NumSamples;i++)
+ {
+ FSample *sample = &self->Samples[i];
+ ALfontsound *sound = sample->Sound;
+ fluid_voice_t *voice;
+ ALsizei m;
+
+ if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity))
+ continue;
+
+ voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
+ if(voice == NULL)
+ return FLUID_FAILED;
+
+ fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
+ fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
+ fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch);
+ fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff);
+ fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ);
+ fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff);
+ fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff);
+ fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume);
+ fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend);
+ fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend);
+ fluid_voice_gen_set(voice, GEN_PAN, sound->Pan);
+ fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay);
+ fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency);
+ fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay);
+ fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency);
+ fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime);
+ fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime);
+ fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime);
+ fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime);
+ fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn);
+ fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime);
+ fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime);
+ fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime);
+ fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime);
+ fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime);
+ fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime);
+ fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime);
+ fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn);
+ fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime);
+ fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime);
+ fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime);
+ fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation);
+ fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning);
+ fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning);
+ fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode));
+ fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale);
+ fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass);
+ for(m = 0;m < sample->NumMods;m++)
+ fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE);
+
+ fluid_synth_start_voice(synth, voice);
+ }
+
+ return FLUID_OK;
+}
+
+
+typedef struct FSfont {
+ DERIVE_FROM_TYPE(fluid_sfont_t);
+
+ char Name[16];
+
+ FPreset *Presets;
+ ALsizei NumPresets;
+
+ ALsizei CurrentPos;
+} FSfont;
+
+static int FSfont_free(fluid_sfont_t *sfont);
+static char* FSfont_getName(fluid_sfont_t *sfont);
+static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum);
+static void FSfont_iterStart(fluid_sfont_t *sfont);
+static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset);
+
+static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
+{
+ STATIC_CAST(fluid_sfont_t, self)->data = self;
+ STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED;
+ STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free;
+ STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName;
+ STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset;
+ STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart;
+ STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext;
+
+ memset(self->Name, 0, sizeof(self->Name));
+ self->CurrentPos = 0;
+ self->NumPresets = 0;
+ self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0]));
+ if(self->Presets)
+ {
+ ALsizei i;
+ self->NumPresets = sfont->NumPresets;
+ for(i = 0;i < self->NumPresets;i++)
+ FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self), sfont);
+ }
+}
+
+static void FSfont_Destruct(FSfont *self)
+{
+ ALsizei i;
+
+ for(i = 0;i < self->NumPresets;i++)
+ FPreset_Destruct(&self->Presets[i]);
+ free(self->Presets);
+ self->Presets = NULL;
+ self->NumPresets = 0;
+ self->CurrentPos = 0;
+}
+
+static int FSfont_free(fluid_sfont_t *sfont)
+{
+ FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
+ ALsizei i;
+
+ for(i = 0;i < self->NumPresets;i++)
+ {
+ if(!FPreset_canDelete(&self->Presets[i]))
+ return 1;
+ }
+
+ FSfont_Destruct(self);
+ free(self);
+ return 0;
+}
+
+static char* FSfont_getName(fluid_sfont_t *sfont)
+{
+ return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name;
+}
+
+static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum)
+{
+ FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
+ ALsizei i;
+
+ for(i = 0;i < self->NumPresets;i++)
+ {
+ FPreset *preset = &self->Presets[i];
+ if(preset->Bank == (int)bank && preset->Preset == (int)prenum)
+ return STATIC_CAST(fluid_preset_t, preset);
+ }
+
+ return NULL;
+}
+
+static void FSfont_iterStart(fluid_sfont_t *sfont)
+{
+ STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0;
+}
+
+static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset)
+{
+ FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
+ if(self->CurrentPos >= self->NumPresets)
+ return 0;
+ *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]);
+ preset->free = NULL;
+ return 1;
+}
+
+
+typedef struct FSynth {
+ DERIVE_FROM_TYPE(MidiSynth);
+ DERIVE_FROM_TYPE(fluid_sfloader_t);
+
+ fluid_settings_t *Settings;
+ fluid_synth_t *Synth;
+ int *FontIDs;
+ ALsizei NumFontIDs;
+
+ ALboolean ForceGM2BankSelect;
+ ALfloat GainScale;
+} FSynth;
+
+static void FSynth_Construct(FSynth *self, ALCdevice *device);
+static void FSynth_Destruct(FSynth *self);
+static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
+static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
+static void FSynth_setGain(FSynth *self, ALfloat gain);
+static void FSynth_setState(FSynth *self, ALenum state);
+static void FSynth_stop(FSynth *self);
+static void FSynth_reset(FSynth *self);
+static void FSynth_update(FSynth *self, ALCdevice *device);
+static void FSynth_processQueue(FSynth *self, ALuint64 time);
+static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
+static void FSynth_Delete(FSynth *self);
+DEFINE_MIDISYNTH_VTABLE(FSynth);
+
+static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
+
+
+static void FSynth_Construct(FSynth *self, ALCdevice *device)
+{
+ MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
+ SET_VTABLE2(FSynth, MidiSynth, self);
+
+ STATIC_CAST(fluid_sfloader_t, self)->data = self;
+ STATIC_CAST(fluid_sfloader_t, self)->free = NULL;
+ STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont;
+
+ self->Settings = NULL;
+ self->Synth = NULL;
+ self->FontIDs = NULL;
+ self->NumFontIDs = 0;
+ self->ForceGM2BankSelect = AL_FALSE;
+ self->GainScale = 0.2f;
+}
+
+static void FSynth_Destruct(FSynth *self)
+{
+ ALsizei i;
+
+ for(i = 0;i < self->NumFontIDs;i++)
+ fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0);
+ free(self->FontIDs);
+ self->FontIDs = NULL;
+ self->NumFontIDs = 0;
+
+ if(self->Synth != NULL)
+ delete_fluid_synth(self->Synth);
+ self->Synth = NULL;
+
+ if(self->Settings != NULL)
+ delete_fluid_settings(self->Settings);
+ self->Settings = NULL;
+
+ MidiSynth_Destruct(STATIC_CAST(MidiSynth, self));
+}
+
+static ALboolean FSynth_init(FSynth *self, ALCdevice *device)
+{
+ ALfloat vol;
+
+ if(ConfigValueFloat("midi", "volume", &vol))
+ {
+ if(!(vol <= 0.0f))
+ {
+ ERR("MIDI volume %f clamped to 0\n", vol);
+ vol = 0.0f;
+ }
+ self->GainScale = powf(10.0f, vol / 20.0f);
+ }
+
+ self->Settings = new_fluid_settings();
+ if(!self->Settings)
+ {
+ ERR("Failed to create FluidSettings\n");
+ return AL_FALSE;
+ }
+
+ fluid_settings_setint(self->Settings, "synth.polyphony", 256);
+ fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale);
+ fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
+
+ self->Synth = new_fluid_synth(self->Settings);
+ if(!self->Synth)
+ {
+ ERR("Failed to create FluidSynth\n");
+ return AL_FALSE;
+ }
+
+ fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self));
+
+ return AL_TRUE;
+}
+
+
+static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename)
+{
+ FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader);
+ FSfont *sfont;
+ int idx;
+
+ if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1)
+ return NULL;
+ if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts)
+ {
+ ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts);
+ return NULL;
+ }
+
+ sfont = calloc(1, sizeof(sfont[0]));
+ if(!sfont) return NULL;
+
+ FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]);
+ return STATIC_CAST(fluid_sfont_t, sfont);
+}
+
+static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
+{
+ int *fontid;
+ ALenum ret;
+ ALsizei i;
+
+ ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids);
+ if(ret != AL_NO_ERROR) return ret;
+
+ ALCdevice_Lock(context->Device);
+ for(i = 0;i < 16;i++)
+ fluid_synth_all_sounds_off(self->Synth, i);
+ ALCdevice_Unlock(context->Device);
+
+ fontid = malloc(count * sizeof(fontid[0]));
+ if(fontid)
+ {
+ for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++)
+ {
+ char name[16];
+ snprintf(name, sizeof(name), "_al_internal %d", i);
+
+ fontid[i] = fluid_synth_sfload(self->Synth, name, 0);
+ if(fontid[i] == FLUID_FAILED)
+ ERR("Failed to load selected soundfont %d\n", i);
+ }
+
+ fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid);
+ count = ExchangeInt(&self->NumFontIDs, count);
+ }
+ else
+ {
+ ERR("Failed to allocate space for %d font IDs!\n", count);
+ fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL);
+ count = ExchangeInt(&self->NumFontIDs, 0);
+ }
+
+ for(i = 0;i < count;i++)
+ fluid_synth_sfunload(self->Synth, fontid[i], 0);
+ free(fontid);
+
+ return ret;
+}
+
+
+static void FSynth_setGain(FSynth *self, ALfloat gain)
+{
+ fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale * gain);
+ fluid_synth_set_gain(self->Synth, self->GainScale * gain);
+ MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain);
+}
+
+
+static void FSynth_setState(FSynth *self, ALenum state)
+{
+ MidiSynth_setState(STATIC_CAST(MidiSynth, self), state);
+}
+
+static void FSynth_stop(FSynth *self)
+{
+ MidiSynth *synth = STATIC_CAST(MidiSynth, self);
+ ALsizei chan;
+
+ /* Make sure all pending events are processed. */
+ while(!(synth->SamplesToNext >= 1.0))
+ {
+ ALuint64 time = synth->NextEvtTime;
+ if(time == UINT64_MAX)
+ break;
+
+ synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
+ synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
+ synth->LastEvtTime = time;
+ FSynth_processQueue(self, time);
+
+ synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
+ if(synth->NextEvtTime != UINT64_MAX)
+ synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
+ }
+
+ /* All notes off */
+ for(chan = 0;chan < 16;chan++)
+ fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0);
+
+ MidiSynth_stop(STATIC_CAST(MidiSynth, self));
+}
+
+static void FSynth_reset(FSynth *self)
+{
+ /* Reset to power-up status. */
+ fluid_synth_system_reset(self->Synth);
+
+ MidiSynth_reset(STATIC_CAST(MidiSynth, self));
+}
+
+
+static void FSynth_update(FSynth *self, ALCdevice *device)
+{
+ fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
+ fluid_synth_set_sample_rate(self->Synth, device->Frequency);
+ MidiSynth_update(STATIC_CAST(MidiSynth, self), device);
+}
+
+
+static void FSynth_processQueue(FSynth *self, ALuint64 time)
+{
+ EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
+
+ while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
+ {
+ const MidiEvent *evt = &queue->events[queue->pos];
+
+ if(evt->event == SYSEX_EVENT)
+ {
+ static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 };
+ static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 };
+ int handled = 0;
+
+ fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0);
+ if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on))
+ {
+ if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0)
+ self->ForceGM2BankSelect = AL_TRUE;
+ else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0)
+ self->ForceGM2BankSelect = AL_FALSE;
+ }
+ }
+ else switch((evt->event&0xF0))
+ {
+ case AL_NOTEOFF_SOFT:
+ fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]);
+ break;
+ case AL_NOTEON_SOFT:
+ fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
+ break;
+ case AL_KEYPRESSURE_SOFT:
+ break;
+
+ case AL_CONTROLLERCHANGE_SOFT:
+ if(self->ForceGM2BankSelect)
+ {
+ int chan = (evt->event&0x0F);
+ if(evt->param.val[0] == CTRL_BANKSELECT_MSB)
+ {
+ if(evt->param.val[1] == 120 && (chan == 9 || chan == 10))
+ fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM);
+ else if(evt->param.val[1] == 121)
+ fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC);
+ break;
+ }
+ if(evt->param.val[0] == CTRL_BANKSELECT_LSB)
+ {
+ fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]);
+ break;
+ }
+ }
+ fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
+ break;
+ case AL_PROGRAMCHANGE_SOFT:
+ fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]);
+ break;
+
+ case AL_CHANNELPRESSURE_SOFT:
+ fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]);
+ break;
+
+ case AL_PITCHBEND_SOFT:
+ fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) |
+ ((evt->param.val[1]&0x7F)<<7));
+ break;
+ }
+
+ queue->pos++;
+ }
+}
+
+static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
+{
+ MidiSynth *synth = STATIC_CAST(MidiSynth, self);
+ ALenum state = synth->State;
+ ALuint total = 0;
+
+ if(state == AL_INITIAL)
+ return;
+ if(state != AL_PLAYING)
+ {
+ fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
+ DryBuffer[FrontRight], 0, 1);
+ return;
+ }
+
+ while(total < SamplesToDo)
+ {
+ if(synth->SamplesToNext >= 1.0)
+ {
+ ALuint todo = minu(SamplesToDo - total, fastf2u(synth->SamplesToNext));
+
+ fluid_synth_write_float(self->Synth, todo,
+ &DryBuffer[FrontLeft][total], 0, 1,
+ &DryBuffer[FrontRight][total], 0, 1);
+ total += todo;
+ synth->SamplesSinceLast += todo;
+ synth->SamplesToNext -= todo;
+ }
+ else
+ {
+ ALuint64 time = synth->NextEvtTime;
+ if(time == UINT64_MAX)
+ {
+ synth->SamplesSinceLast += SamplesToDo-total;
+ fluid_synth_write_float(self->Synth, SamplesToDo-total,
+ &DryBuffer[FrontLeft][total], 0, 1,
+ &DryBuffer[FrontRight][total], 0, 1);
+ break;
+ }
+
+ synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
+ synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
+ synth->LastEvtTime = time;
+ FSynth_processQueue(self, time);
+
+ synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
+ if(synth->NextEvtTime != UINT64_MAX)
+ synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
+ }
+ }
+}
+
+
+static void FSynth_Delete(FSynth *self)
+{
+ free(self);
+}
+
+
+MidiSynth *FSynth_create(ALCdevice *device)
+{
+ FSynth *synth = calloc(1, sizeof(*synth));
+ if(!synth)
+ {
+ ERR("Failed to allocate FSynth\n");
+ return NULL;
+ }
+ FSynth_Construct(synth, device);
+
+ if(FSynth_init(synth, device) == AL_FALSE)
+ {
+ DELETE_OBJ(STATIC_CAST(MidiSynth, synth));
+ return NULL;
+ }
+
+ return STATIC_CAST(MidiSynth, synth);
+}
+
+#else
+
+MidiSynth *FSynth_create(ALCdevice* UNUSED(device))
+{
+ return NULL;
+}
+
+#endif
diff --git a/Alc/midi/sf2load.c b/Alc/midi/sf2load.c
new file mode 100644
index 00000000..5bba345f
--- /dev/null
+++ b/Alc/midi/sf2load.c
@@ -0,0 +1,1436 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alMidi.h"
+#include "alError.h"
+#include "alu.h"
+
+#include "midi/base.h"
+
+
+static ALuint read_le32(Reader *stream)
+{
+ ALubyte buf[4];
+ if(READ(stream, buf, 4) != 4)
+ {
+ READERR(stream) = 1;
+ return 0;
+ }
+ return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
+}
+static ALushort read_le16(Reader *stream)
+{
+ ALubyte buf[2];
+ if(READ(stream, buf, 2) != 2)
+ {
+ READERR(stream) = 1;
+ return 0;
+ }
+ return (buf[1]<<8) | buf[0];
+}
+static ALubyte read_8(Reader *stream)
+{
+ ALubyte buf[1];
+ if(READ(stream, buf, 1) != 1)
+ {
+ READERR(stream) = 1;
+ return 0;
+ }
+ return buf[0];
+}
+static void skip(Reader *stream, ALuint amt)
+{
+ while(amt > 0 && !READERR(stream))
+ {
+ char buf[4096];
+ size_t got;
+
+ got = READ(stream, buf, minu(sizeof(buf), amt));
+ if(got == 0) READERR(stream) = 1;
+
+ amt -= got;
+ }
+}
+
+typedef struct Generator {
+ ALushort mGenerator;
+ ALushort mAmount;
+} Generator;
+static void Generator_read(Generator *self, Reader *stream)
+{
+ self->mGenerator = read_le16(stream);
+ self->mAmount = read_le16(stream);
+}
+
+static const ALint DefaultGenValue[60] = {
+ 0, /* 0 - startAddrOffset */
+ 0, /* 1 - endAddrOffset */
+ 0, /* 2 - startloopAddrOffset */
+ 0, /* 3 - endloopAddrOffset */
+ 0, /* 4 - startAddrCoarseOffset */
+ 0, /* 5 - modLfoToPitch */
+ 0, /* 6 - vibLfoToPitch */
+ 0, /* 7 - modEnvToPitch */
+ 13500, /* 8 - initialFilterFc */
+ 0, /* 9 - initialFilterQ */
+ 0, /* 10 - modLfoToFilterFc */
+ 0, /* 11 - modEnvToFilterFc */
+ 0, /* 12 - endAddrCoarseOffset */
+ 0, /* 13 - modLfoToVolume */
+ 0, /* 14 - */
+ 0, /* 15 - chorusEffectsSend */
+ 0, /* 16 - reverbEffectsSend */
+ 0, /* 17 - pan */
+ 0, /* 18 - */
+ 0, /* 19 - */
+ 0, /* 20 - */
+ -12000, /* 21 - delayModLFO */
+ 0, /* 22 - freqModLFO */
+ -12000, /* 23 - delayVibLFO */
+ 0, /* 24 - freqVibLFO */
+ -12000, /* 25 - delayModEnv */
+ -12000, /* 26 - attackModEnv */
+ -12000, /* 27 - holdModEnv */
+ -12000, /* 28 - decayModEnv */
+ 0, /* 29 - sustainModEnv */
+ -12000, /* 30 - releaseModEnv */
+ 0, /* 31 - keynumToModEnvHold */
+ 0, /* 32 - keynumToModEnvDecay */
+ -12000, /* 33 - delayVolEnv */
+ -12000, /* 34 - attackVolEnv */
+ -12000, /* 35 - holdVolEnv */
+ -12000, /* 36 - decayVolEnv */
+ 0, /* 37 - sustainVolEnv */
+ -12000, /* 38 - releaseVolEnv */
+ 0, /* 39 - keynumToVolEnvHold */
+ 0, /* 40 - keynumToVolEnvDecay */
+ 0, /* 41 - */
+ 0, /* 42 - */
+ 0, /* 43 - keyRange */
+ 0, /* 44 - velRange */
+ 0, /* 45 - startloopAddrCoarseOffset */
+ 0, /* 46 - keynum */
+ 0, /* 47 - velocity */
+ 0, /* 48 - initialAttenuation */
+ 0, /* 49 - */
+ 0, /* 50 - endloopAddrCoarseOffset */
+ 0, /* 51 - corseTune */
+ 0, /* 52 - fineTune */
+ 0, /* 53 - */
+ 0, /* 54 - sampleModes */
+ 0, /* 55 - */
+ 100, /* 56 - scaleTuning */
+ 0, /* 57 - exclusiveClass */
+ 0, /* 58 - overridingRootKey */
+ 0, /* 59 - */
+};
+
+typedef struct Modulator {
+ ALushort mSrcOp;
+ ALushort mDstOp;
+ ALshort mAmount;
+ ALushort mAmtSrcOp;
+ ALushort mTransOp;
+} Modulator;
+static void Modulator_read(Modulator *self, Reader *stream)
+{
+ self->mSrcOp = read_le16(stream);
+ self->mDstOp = read_le16(stream);
+ self->mAmount = read_le16(stream);
+ self->mAmtSrcOp = read_le16(stream);
+ self->mTransOp = read_le16(stream);
+}
+
+typedef struct Zone {
+ ALushort mGenIdx;
+ ALushort mModIdx;
+} Zone;
+static void Zone_read(Zone *self, Reader *stream)
+{
+ self->mGenIdx = read_le16(stream);
+ self->mModIdx = read_le16(stream);
+}
+
+typedef struct PresetHeader {
+ ALchar mName[20];
+ ALushort mPreset; /* MIDI program number */
+ ALushort mBank;
+ ALushort mZoneIdx;
+ ALuint mLibrary;
+ ALuint mGenre;
+ ALuint mMorphology;
+} PresetHeader;
+static void PresetHeader_read(PresetHeader *self, Reader *stream)
+{
+ if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
+ READERR(stream) = 1;
+ self->mPreset = read_le16(stream);
+ self->mBank = read_le16(stream);
+ self->mZoneIdx = read_le16(stream);
+ self->mLibrary = read_le32(stream);
+ self->mGenre = read_le32(stream);
+ self->mMorphology = read_le32(stream);
+}
+
+typedef struct InstrumentHeader {
+ ALchar mName[20];
+ ALushort mZoneIdx;
+} InstrumentHeader;
+static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream)
+{
+ if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
+ READERR(stream) = 1;
+ self->mZoneIdx = read_le16(stream);
+}
+
+typedef struct SampleHeader {
+ ALchar mName[20]; // 20 bytes
+ ALuint mStart;
+ ALuint mEnd;
+ ALuint mStartloop;
+ ALuint mEndloop;
+ ALuint mSampleRate;
+ ALubyte mOriginalKey;
+ ALbyte mCorrection;
+ ALushort mSampleLink;
+ ALushort mSampleType;
+} SampleHeader;
+static void SampleHeader_read(SampleHeader *self, Reader *stream)
+{
+ if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
+ READERR(stream) = 1;
+ self->mStart = read_le32(stream);
+ self->mEnd = read_le32(stream);
+ self->mStartloop = read_le32(stream);
+ self->mEndloop = read_le32(stream);
+ self->mSampleRate = read_le32(stream);
+ self->mOriginalKey = read_8(stream);
+ self->mCorrection = read_8(stream);
+ self->mSampleLink = read_le16(stream);
+ self->mSampleType = read_le16(stream);
+}
+
+
+typedef struct Soundfont {
+ ALuint ifil;
+ ALchar *irom;
+
+ PresetHeader *phdr;
+ ALsizei phdr_size;
+
+ Zone *pbag;
+ ALsizei pbag_size;
+ Modulator *pmod;
+ ALsizei pmod_size;
+ Generator *pgen;
+ ALsizei pgen_size;
+
+ InstrumentHeader *inst;
+ ALsizei inst_size;
+
+ Zone *ibag;
+ ALsizei ibag_size;
+ Modulator *imod;
+ ALsizei imod_size;
+ Generator *igen;
+ ALsizei igen_size;
+
+ SampleHeader *shdr;
+ ALsizei shdr_size;
+} Soundfont;
+
+static void Soundfont_Construct(Soundfont *self)
+{
+ self->ifil = 0;
+ self->irom = NULL;
+
+ self->phdr = NULL;
+ self->phdr_size = 0;
+
+ self->pbag = NULL;
+ self->pbag_size = 0;
+ self->pmod = NULL;
+ self->pmod_size = 0;
+ self->pgen = NULL;
+ self->pgen_size = 0;
+
+ self->inst = NULL;
+ self->inst_size = 0;
+
+ self->ibag = NULL;
+ self->ibag_size = 0;
+ self->imod = NULL;
+ self->imod_size = 0;
+ self->igen = NULL;
+ self->igen_size = 0;
+
+ self->shdr = NULL;
+ self->shdr_size = 0;
+}
+
+static void Soundfont_Destruct(Soundfont *self)
+{
+ free(self->irom);
+ self->irom = NULL;
+
+ free(self->phdr);
+ self->phdr = NULL;
+ self->phdr_size = 0;
+
+ free(self->pbag);
+ self->pbag = NULL;
+ self->pbag_size = 0;
+ free(self->pmod);
+ self->pmod = NULL;
+ self->pmod_size = 0;
+ free(self->pgen);
+ self->pgen = NULL;
+ self->pgen_size = 0;
+
+ free(self->inst);
+ self->inst = NULL;
+ self->inst_size = 0;
+
+ free(self->ibag);
+ self->ibag = NULL;
+ self->ibag_size = 0;
+ free(self->imod);
+ self->imod = NULL;
+ self->imod_size = 0;
+ free(self->igen);
+ self->igen = NULL;
+ self->igen_size = 0;
+
+ free(self->shdr);
+ self->shdr = NULL;
+ self->shdr_size = 0;
+}
+
+
+#define FOURCC(a,b,c,d) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a))
+#define FOURCCARGS(x) (char)((x)&0xff), (char)(((x)>>8)&0xff), (char)(((x)>>16)&0xff), (char)(((x)>>24)&0xff)
+typedef struct RiffHdr {
+ ALuint mCode;
+ ALuint mSize;
+} RiffHdr;
+static void RiffHdr_read(RiffHdr *self, Reader *stream)
+{
+ self->mCode = read_le32(stream);
+ self->mSize = read_le32(stream);
+}
+
+
+typedef struct GenModList {
+ Generator *gens;
+ ALsizei gens_size;
+ ALsizei gens_max;
+
+ Modulator *mods;
+ ALsizei mods_size;
+ ALsizei mods_max;
+} GenModList;
+
+static void GenModList_Construct(GenModList *self)
+{
+ self->gens = NULL;
+ self->gens_size = 0;
+ self->gens_max = 0;
+
+ self->mods = NULL;
+ self->mods_size = 0;
+ self->mods_max = 0;
+}
+
+static void GenModList_Destruct(GenModList *self)
+{
+ free(self->gens);
+ self->gens = NULL;
+ self->gens_size = 0;
+ self->gens_max = 0;
+
+ free(self->mods);
+ self->mods = NULL;
+ self->mods_size = 0;
+ self->mods_max = 0;
+}
+
+static GenModList GenModList_clone(const GenModList *self)
+{
+ GenModList ret;
+
+ ret.gens = malloc(self->gens_max * sizeof(ret.gens[0]));
+ memcpy(ret.gens, self->gens, self->gens_size * sizeof(ret.gens[0]));
+ ret.gens_size = self->gens_size;
+ ret.gens_max = self->gens_max;
+
+ ret.mods = malloc(self->mods_max * sizeof(ret.mods[0]));
+ memcpy(ret.mods, self->mods, self->mods_size * sizeof(ret.mods[0]));
+ ret.mods_size = self->mods_size;
+ ret.mods_max = self->mods_max;
+
+ return ret;
+}
+
+static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset)
+{
+ Generator *i = self->gens;
+ Generator *end = i + self->gens_size;
+ for(;i != end;i++)
+ {
+ if(i->mGenerator == gen->mGenerator)
+ {
+ i->mAmount = gen->mAmount;
+ return;
+ }
+ }
+
+ if(ispreset &&
+ (gen->mGenerator == 0 || gen->mGenerator == 1 || gen->mGenerator == 2 ||
+ gen->mGenerator == 3 || gen->mGenerator == 4 || gen->mGenerator == 12 ||
+ gen->mGenerator == 45 || gen->mGenerator == 46 || gen->mGenerator == 47 ||
+ gen->mGenerator == 50 || gen->mGenerator == 54 || gen->mGenerator == 57 ||
+ gen->mGenerator == 58))
+ return;
+
+ if(self->gens_size == self->gens_max)
+ {
+ void *temp = NULL;
+ ALsizei newsize;
+
+ newsize = (self->gens_max ? self->gens_max<<1 : 1);
+ if(newsize > self->gens_max)
+ temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
+ if(!temp)
+ {
+ ERR("Failed to increase generator storage to %d elements (from %d)\n",
+ newsize, self->gens_max);
+ return;
+ }
+
+ self->gens = temp;
+ self->gens_max = newsize;
+ }
+
+ self->gens[self->gens_size] = *gen;
+ self->gens_size++;
+}
+static void GenModList_accumGen(GenModList *self, const Generator *gen)
+{
+ Generator *i = self->gens;
+ Generator *end = i + self->gens_size;
+ for(;i != end;i++)
+ {
+ if(i->mGenerator == gen->mGenerator)
+ {
+ if(gen->mGenerator == 43 || gen->mGenerator == 44)
+ {
+ /* Range generators accumulate by taking the intersection of
+ * the two ranges.
+ */
+ ALushort low = maxu(i->mAmount&0x00ff, gen->mAmount&0x00ff);
+ ALushort high = minu(i->mAmount&0xff00, gen->mAmount&0xff00);
+ i->mAmount = low | high;
+ }
+ else
+ i->mAmount += gen->mAmount;
+ return;
+ }
+ }
+
+ if(self->gens_size == self->gens_max)
+ {
+ void *temp = NULL;
+ ALsizei newsize;
+
+ newsize = (self->gens_max ? self->gens_max<<1 : 1);
+ if(newsize > self->gens_max)
+ temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
+ if(!temp)
+ {
+ ERR("Failed to increase generator storage to %d elements (from %d)\n",
+ newsize, self->gens_max);
+ return;
+ }
+
+ self->gens = temp;
+ self->gens_max = newsize;
+ }
+
+ self->gens[self->gens_size] = *gen;
+ if(gen->mGenerator < 60)
+ self->gens[self->gens_size].mAmount += DefaultGenValue[gen->mGenerator];
+ self->gens_size++;
+}
+
+static void GenModList_insertMod(GenModList *self, const Modulator *mod)
+{
+ Modulator *i = self->mods;
+ Modulator *end = i + self->mods_size;
+ for(;i != end;i++)
+ {
+ if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
+ i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
+ {
+ i->mAmount = mod->mAmount;
+ return;
+ }
+ }
+
+ if(self->mods_size == self->mods_max)
+ {
+ void *temp = NULL;
+ ALsizei newsize;
+
+ newsize = (self->mods_max ? self->mods_max<<1 : 1);
+ if(newsize > self->mods_max)
+ temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
+ if(!temp)
+ {
+ ERR("Failed to increase modulator storage to %d elements (from %d)\n",
+ newsize, self->mods_max);
+ return;
+ }
+
+ self->mods = temp;
+ self->mods_max = newsize;
+ }
+
+ self->mods[self->mods_size] = *mod;
+ self->mods_size++;
+}
+static void GenModList_accumMod(GenModList *self, const Modulator *mod)
+{
+ Modulator *i = self->mods;
+ Modulator *end = i + self->mods_size;
+ for(;i != end;i++)
+ {
+ if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
+ i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
+ {
+ i->mAmount += mod->mAmount;
+ return;
+ }
+ }
+
+ if(self->mods_size == self->mods_max)
+ {
+ void *temp = NULL;
+ ALsizei newsize;
+
+ newsize = (self->mods_max ? self->mods_max<<1 : 1);
+ if(newsize > self->mods_max)
+ temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
+ if(!temp)
+ {
+ ERR("Failed to increase modulator storage to %d elements (from %d)\n",
+ newsize, self->mods_max);
+ return;
+ }
+
+ self->mods = temp;
+ self->mods_max = newsize;
+ }
+
+ self->mods[self->mods_size] = *mod;
+ if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 960;
+ else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += -2400;
+ else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 50;
+ else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 50;
+ else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 960;
+ else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 1000;
+ else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 960;
+ else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 200;
+ else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 200;
+ /*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0)
+ self->mods[self->mods_size].mAmount += 12700;*/
+ self->mods_size++;
+}
+
+
+#define ERROR_GOTO(lbl_, ...) do { \
+ ERR(__VA_ARGS__); \
+ goto lbl_; \
+} while(0)
+
+static ALboolean ensureFontSanity(const Soundfont *sfont)
+{
+ ALsizei i;
+
+ for(i = 0;i < sfont->phdr_size-1;i++)
+ {
+ if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size)
+ {
+ WARN("Preset %d has invalid zone index %d (max: %d)\n", i,
+ sfont->phdr[i].mZoneIdx, sfont->pbag_size);
+ return AL_FALSE;
+ }
+ if(sfont->phdr[i+1].mZoneIdx < sfont->phdr[i].mZoneIdx)
+ {
+ WARN("Preset %d has invalid zone index (%d does not follow %d)\n", i+1,
+ sfont->phdr[i+1].mZoneIdx, sfont->phdr[i].mZoneIdx);
+ return AL_FALSE;
+ }
+ }
+ if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size)
+ {
+ WARN("Preset %d has invalid zone index %d (max: %d)\n", i,
+ sfont->phdr[i].mZoneIdx, sfont->pbag_size);
+ return AL_FALSE;
+ }
+
+ for(i = 0;i < sfont->pbag_size-1;i++)
+ {
+ if(sfont->pbag[i].mGenIdx >= sfont->pgen_size)
+ {
+ WARN("Preset zone %d has invalid generator index %d (max: %d)\n", i,
+ sfont->pbag[i].mGenIdx, sfont->pgen_size);
+ return AL_FALSE;
+ }
+ if(sfont->pbag[i+1].mGenIdx < sfont->pbag[i].mGenIdx)
+ {
+ WARN("Preset zone %d has invalid generator index (%d does not follow %d)\n", i+1,
+ sfont->pbag[i+1].mGenIdx, sfont->pbag[i].mGenIdx);
+ return AL_FALSE;
+ }
+ if(sfont->pbag[i].mModIdx >= sfont->pmod_size)
+ {
+ WARN("Preset zone %d has invalid modulator index %d (max: %d)\n", i,
+ sfont->pbag[i].mModIdx, sfont->pmod_size);
+ return AL_FALSE;
+ }
+ if(sfont->pbag[i+1].mModIdx < sfont->pbag[i].mModIdx)
+ {
+ WARN("Preset zone %d has invalid modulator index (%d does not follow %d)\n", i+1,
+ sfont->pbag[i+1].mModIdx, sfont->pbag[i].mModIdx);
+ return AL_FALSE;
+ }
+ }
+ if(sfont->pbag[i].mGenIdx >= sfont->pgen_size)
+ {
+ WARN("Preset zone %d has invalid generator index %d (max: %d)\n", i,
+ sfont->pbag[i].mGenIdx, sfont->pgen_size);
+ return AL_FALSE;
+ }
+ if(sfont->pbag[i].mModIdx >= sfont->pmod_size)
+ {
+ WARN("Preset zone %d has invalid modulator index %d (max: %d)\n", i,
+ sfont->pbag[i].mModIdx, sfont->pmod_size);
+ return AL_FALSE;
+ }
+
+
+ for(i = 0;i < sfont->inst_size-1;i++)
+ {
+ if(sfont->inst[i].mZoneIdx >= sfont->ibag_size)
+ {
+ WARN("Instrument %d has invalid zone index %d (max: %d)\n", i,
+ sfont->inst[i].mZoneIdx, sfont->ibag_size);
+ return AL_FALSE;
+ }
+ if(sfont->inst[i+1].mZoneIdx < sfont->inst[i].mZoneIdx)
+ {
+ WARN("Instrument %d has invalid zone index (%d does not follow %d)\n", i+1,
+ sfont->inst[i+1].mZoneIdx, sfont->inst[i].mZoneIdx);
+ return AL_FALSE;
+ }
+ }
+ if(sfont->inst[i].mZoneIdx >= sfont->ibag_size)
+ {
+ WARN("Instrument %d has invalid zone index %d (max: %d)\n", i,
+ sfont->inst[i].mZoneIdx, sfont->ibag_size);
+ return AL_FALSE;
+ }
+
+ for(i = 0;i < sfont->ibag_size-1;i++)
+ {
+ if(sfont->ibag[i].mGenIdx >= sfont->igen_size)
+ {
+ WARN("Instrument zone %d has invalid generator index %d (max: %d)\n", i,
+ sfont->ibag[i].mGenIdx, sfont->igen_size);
+ return AL_FALSE;
+ }
+ if(sfont->ibag[i+1].mGenIdx < sfont->ibag[i].mGenIdx)
+ {
+ WARN("Instrument zone %d has invalid generator index (%d does not follow %d)\n", i+1,
+ sfont->ibag[i+1].mGenIdx, sfont->ibag[i].mGenIdx);
+ return AL_FALSE;
+ }
+ if(sfont->ibag[i].mModIdx >= sfont->imod_size)
+ {
+ WARN("Instrument zone %d has invalid modulator index %d (max: %d)\n", i,
+ sfont->ibag[i].mModIdx, sfont->imod_size);
+ return AL_FALSE;
+ }
+ if(sfont->ibag[i+1].mModIdx < sfont->ibag[i].mModIdx)
+ {
+ WARN("Instrument zone %d has invalid modulator index (%d does not follow %d)\n", i+1,
+ sfont->ibag[i+1].mModIdx, sfont->ibag[i].mModIdx);
+ return AL_FALSE;
+ }
+ }
+ if(sfont->ibag[i].mGenIdx >= sfont->igen_size)
+ {
+ WARN("Instrument zone %d has invalid generator index %d (max: %d)\n", i,
+ sfont->ibag[i].mGenIdx, sfont->igen_size);
+ return AL_FALSE;
+ }
+ if(sfont->ibag[i].mModIdx >= sfont->imod_size)
+ {
+ WARN("Instrument zone %d has invalid modulator index %d (max: %d)\n", i,
+ sfont->ibag[i].mModIdx, sfont->imod_size);
+ return AL_FALSE;
+ }
+
+
+ for(i = 0;i < sfont->shdr_size-1;i++)
+ {
+ if((sfont->shdr[i].mSampleType&0x8000) && sfont->irom == NULL)
+ {
+ WARN("Sample header %d has ROM sample type without an irom sub-chunk\n", i);
+ return AL_FALSE;
+ }
+ }
+
+
+ return AL_TRUE;
+}
+
+static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp)
+{
+ ALsizei i;
+
+ for(i = 0;i < zone->gens_size;i++)
+ {
+ if(zone->gens[i].mGenerator == 43 || zone->gens[i].mGenerator == 44)
+ {
+ int high = zone->gens[i].mAmount>>8;
+ int low = zone->gens[i].mAmount&0xff;
+
+ if(!(low >= 0 && high <= 127 && high >= low))
+ {
+ TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n",
+ preset->mName, inst->mName, samp->mName,
+ (zone->gens[i].mGenerator == 43) ? "key" :
+ (zone->gens[i].mGenerator == 44) ? "velocity" : "(unknown)",
+ low, high);
+ return AL_FALSE;
+ }
+ }
+ }
+
+ return AL_TRUE;
+}
+
+static ALenum getModSrcInput(int input)
+{
+ if(input == 0) return AL_ONE_SOFT;
+ if(input == 2) return AL_NOTEON_VELOCITY_SOFT;
+ if(input == 3) return AL_NOTEON_KEY_SOFT;
+ if(input == 10) return AL_KEYPRESSURE_SOFT;
+ if(input == 13) return AL_CHANNELPRESSURE_SOFT;
+ if(input == 14) return AL_PITCHBEND_SOFT;
+ if(input == 16) return AL_PITCHBEND_SENSITIVITY_SOFT;
+ if((input&0x80))
+ {
+ input ^= 0x80;
+ if(input > 0 && input < 120 && !(input == 6 || (input >= 32 && input <= 63) ||
+ (input >= 98 && input <= 101)))
+ return input;
+ input ^= 0x80;
+ }
+ ERR("Unhandled modulator source input: 0x%02x\n", input);
+ return AL_INVALID;
+}
+
+static ALenum getModSrcType(int type)
+{
+ if(type == 0x0000) return AL_UNORM_SOFT;
+ if(type == 0x0100) return AL_UNORM_REV_SOFT;
+ if(type == 0x0200) return AL_SNORM_SOFT;
+ if(type == 0x0300) return AL_SNORM_REV_SOFT;
+ ERR("Unhandled modulator source type: 0x%04x\n", type);
+ return AL_INVALID;
+}
+
+static ALenum getModSrcForm(int form)
+{
+ if(form == 0x0000) return AL_LINEAR_SOFT;
+ if(form == 0x0400) return AL_CONCAVE_SOFT;
+ if(form == 0x0800) return AL_CONVEX_SOFT;
+ if(form == 0x0C00) return AL_SWITCH_SOFT;
+ ERR("Unhandled modulator source form: 0x%04x\n", form);
+ return AL_INVALID;
+}
+
+static ALenum getModTransOp(int op)
+{
+ if(op == 0) return AL_LINEAR_SOFT;
+ if(op == 2) return AL_ABSOLUTE_SOFT;
+ ERR("Unhandled modulator transform op: 0x%04x\n", op);
+ return AL_INVALID;
+}
+
+static ALenum getLoopMode(int mode)
+{
+ if(mode == 0) return AL_NONE;
+ if(mode == 1) return AL_LOOP_CONTINUOUS_SOFT;
+ if(mode == 3) return AL_LOOP_UNTIL_RELEASE_SOFT;
+ ERR("Unhandled loop mode: %d\n", mode);
+ return AL_NONE;
+}
+
+static ALenum getSampleType(int type)
+{
+ if(type == 1) return AL_MONO_SOFT;
+ if(type == 2) return AL_RIGHT_SOFT;
+ if(type == 4) return AL_LEFT_SOFT;
+ if(type == 8)
+ {
+ WARN("Sample type \"linked\" ignored; pretending mono\n");
+ return AL_MONO_SOFT;
+ }
+ ERR("Unhandled sample type: 0x%04x\n", type);
+ return AL_MONO_SOFT;
+}
+
+static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *zone)
+{
+ static const ALenum Gen2Param[60] = {
+ 0, /* 0 - startAddrOffset */
+ 0, /* 1 - endAddrOffset */
+ 0, /* 2 - startloopAddrOffset */
+ 0, /* 3 - endloopAddrOffset */
+ 0, /* 4 - startAddrCoarseOffset */
+ AL_MOD_LFO_TO_PITCH_SOFT, /* 5 - modLfoToPitch */
+ AL_VIBRATO_LFO_TO_PITCH_SOFT, /* 6 - vibLfoToPitch */
+ AL_MOD_ENV_TO_PITCH_SOFT, /* 7 - modEnvToPitch */
+ AL_FILTER_CUTOFF_SOFT, /* 8 - initialFilterFc */
+ AL_FILTER_RESONANCE_SOFT, /* 9 - initialFilterQ */
+ AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT, /* 10 - modLfoToFilterFc */
+ AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT, /* 11 - modEnvToFilterFc */
+ 0, /* 12 - endAddrCoarseOffset */
+ AL_MOD_LFO_TO_VOLUME_SOFT, /* 13 - modLfoToVolume */
+ 0, /* 14 - */
+ AL_CHORUS_SEND_SOFT, /* 15 - chorusEffectsSend */
+ AL_REVERB_SEND_SOFT, /* 16 - reverbEffectsSend */
+ AL_PAN_SOFT, /* 17 - pan */
+ 0, /* 18 - */
+ 0, /* 19 - */
+ 0, /* 20 - */
+ AL_MOD_LFO_DELAY_SOFT, /* 21 - delayModLFO */
+ AL_MOD_LFO_FREQUENCY_SOFT, /* 22 - freqModLFO */
+ AL_VIBRATO_LFO_DELAY_SOFT, /* 23 - delayVibLFO */
+ AL_VIBRATO_LFO_FREQUENCY_SOFT, /* 24 - freqVibLFO */
+ AL_MOD_ENV_DELAYTIME_SOFT, /* 25 - delayModEnv */
+ AL_MOD_ENV_ATTACKTIME_SOFT, /* 26 - attackModEnv */
+ AL_MOD_ENV_HOLDTIME_SOFT, /* 27 - holdModEnv */
+ AL_MOD_ENV_DECAYTIME_SOFT, /* 28 - decayModEnv */
+ AL_MOD_ENV_SUSTAINVOLUME_SOFT, /* 29 - sustainModEnv */
+ AL_MOD_ENV_RELEASETIME_SOFT, /* 30 - releaseModEnv */
+ AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT, /* 31 - keynumToModEnvHold */
+ AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT, /* 32 - keynumToModEnvDecay */
+ AL_VOLUME_ENV_DELAYTIME_SOFT, /* 33 - delayVolEnv */
+ AL_VOLUME_ENV_ATTACKTIME_SOFT, /* 34 - attackVolEnv */
+ AL_VOLUME_ENV_HOLDTIME_SOFT, /* 35 - holdVolEnv */
+ AL_VOLUME_ENV_DECAYTIME_SOFT, /* 36 - decayVolEnv */
+ AL_VOLUME_ENV_SUSTAINVOLUME_SOFT, /* 37 - sustainVolEnv */
+ AL_VOLUME_ENV_RELEASETIME_SOFT, /* 38 - releaseVolEnv */
+ AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT, /* 39 - keynumToVolEnvHold */
+ AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT, /* 40 - keynumToVolEnvDecay */
+ 0, /* 41 - */
+ 0, /* 42 - */
+ AL_KEY_RANGE_SOFT, /* 43 - keyRange */
+ AL_VELOCITY_RANGE_SOFT, /* 44 - velRange */
+ 0, /* 45 - startloopAddrCoarseOffset */
+ 0, /* 46 - keynum */
+ 0, /* 47 - velocity */
+ AL_ATTENUATION_SOFT, /* 48 - initialAttenuation */
+ 0, /* 49 - */
+ 0, /* 50 - endloopAddrCoarseOffset */
+ AL_TUNING_COARSE_SOFT, /* 51 - corseTune */
+ AL_TUNING_FINE_SOFT, /* 52 - fineTune */
+ 0, /* 53 - */
+ AL_LOOP_MODE_SOFT, /* 54 - sampleModes */
+ 0, /* 55 - */
+ AL_TUNING_SCALE_SOFT, /* 56 - scaleTuning */
+ AL_EXCLUSIVE_CLASS_SOFT, /* 57 - exclusiveClass */
+ AL_BASE_KEY_SOFT, /* 58 - overridingRootKey */
+ 0, /* 59 - */
+ };
+ const Generator *gen, *gen_end;
+
+ if(zone->mods)
+ {
+ ALsizei i;
+ for(i = 0;i < zone->mods_size;i++)
+ {
+ ALenum src0in = getModSrcInput(zone->mods[i].mSrcOp&0xFF);
+ ALenum src0type = getModSrcType(zone->mods[i].mSrcOp&0x0300);
+ ALenum src0form = getModSrcForm(zone->mods[i].mSrcOp&0xFC00);
+ ALenum src1in = getModSrcInput(zone->mods[i].mAmtSrcOp&0xFF);
+ ALenum src1type = getModSrcType(zone->mods[i].mAmtSrcOp&0x0300);
+ ALenum src1form = getModSrcForm(zone->mods[i].mAmtSrcOp&0xFC00);
+ ALenum trans = getModTransOp(zone->mods[i].mTransOp);
+ ALenum dst = (zone->mods[i].mDstOp < 60) ? Gen2Param[zone->mods[i].mDstOp] : 0;
+ if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT ||
+ dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT ||
+ dst == AL_BASE_KEY_SOFT)
+ ERR("Unhandled modulator destination: %d\n", zone->mods[i].mDstOp);
+ else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID &&
+ src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID &&
+ trans != AL_INVALID)
+ {
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_INPUT_SOFT, src0in);
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_TYPE_SOFT, src0type);
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_FORM_SOFT, src0form);
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_INPUT_SOFT, src1in);
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_TYPE_SOFT, src1type);
+ ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_FORM_SOFT, src1form);
+ ALfontsound_setModStagei(sound, context, i, AL_AMOUNT_SOFT, zone->mods[i].mAmount);
+ ALfontsound_setModStagei(sound, context, i, AL_TRANSFORM_OP_SOFT, trans);
+ ALfontsound_setModStagei(sound, context, i, AL_DESTINATION_SOFT, dst);
+ }
+ }
+ }
+
+ gen = zone->gens;
+ gen_end = gen + zone->gens_size;
+ for(;gen != gen_end;gen++)
+ {
+ ALint value = (ALshort)gen->mAmount;
+ if(gen->mGenerator == 0)
+ sound->Start += value;
+ else if(gen->mGenerator == 1)
+ sound->End += value;
+ else if(gen->mGenerator == 2)
+ sound->LoopStart += value;
+ else if(gen->mGenerator == 3)
+ sound->LoopEnd += value;
+ else if(gen->mGenerator == 4)
+ sound->Start += value<<15;
+ else if(gen->mGenerator == 12)
+ sound->End += value<<15;
+ else if(gen->mGenerator == 45)
+ sound->LoopStart += value<<15;
+ else if(gen->mGenerator == 50)
+ sound->LoopEnd += value<<15;
+ else if(gen->mGenerator == 43)
+ {
+ sound->MinKey = mini((value&0xff), 127);
+ sound->MaxKey = mini(((value>>8)&0xff), 127);
+ }
+ else if(gen->mGenerator == 44)
+ {
+ sound->MinVelocity = mini((value&0xff), 127);
+ sound->MaxVelocity = mini(((value>>8)&0xff), 127);
+ }
+ else
+ {
+ ALenum param = 0;
+ if(gen->mGenerator < 60)
+ param = Gen2Param[gen->mGenerator];
+ if(param)
+ {
+ if(param == AL_BASE_KEY_SOFT)
+ {
+ if(!(value >= 0 && value <= 127))
+ {
+ if(value != -1)
+ WARN("Invalid overridingRootKey generator value %d\n", value);
+ continue;
+ }
+ }
+ if(param == AL_FILTER_RESONANCE_SOFT || param == AL_ATTENUATION_SOFT)
+ value = maxi(0, value);
+ else if(param == AL_CHORUS_SEND_SOFT || param == AL_REVERB_SEND_SOFT)
+ value = clampi(value, 0, 1000);
+ else if(param == AL_LOOP_MODE_SOFT)
+ value = getLoopMode(value);
+ ALfontsound_setPropi(sound, context, param, value);
+ }
+ else if(gen->mGenerator < 256)
+ {
+ static ALboolean warned[256];
+ if(!warned[gen->mGenerator])
+ {
+ warned[gen->mGenerator] = AL_TRUE;
+ ERR("Unhandled generator %d\n", gen->mGenerator);
+ }
+ }
+ }
+ }
+}
+
+static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone)
+{
+ const Generator *gen, *gen_end;
+ const Modulator *mod, *mod_end;
+ const Zone *zone, *zone_end;
+ GenModList gzone;
+ ALvoid *temp;
+
+ if((inst+1)->mZoneIdx == inst->mZoneIdx)
+ ERR("Instrument with no zones!");
+
+ GenModList_Construct(&gzone);
+ zone = sfont->ibag + inst->mZoneIdx;
+ zone_end = sfont->ibag + (inst+1)->mZoneIdx;
+ if(zone_end-zone > 1)
+ {
+ gen = sfont->igen + zone->mGenIdx;
+ gen_end = sfont->igen + (zone+1)->mGenIdx;
+
+ // If no generators, or last generator is not a sample, this is a global zone
+ for(;gen != gen_end;gen++)
+ {
+ if(gen->mGenerator == 53)
+ break;
+ }
+
+ if(gen == gen_end)
+ {
+ gen = sfont->igen + zone->mGenIdx;
+ gen_end = sfont->igen + (zone+1)->mGenIdx;
+ for(;gen != gen_end;gen++)
+ GenModList_insertGen(&gzone, gen, AL_FALSE);
+
+ mod = sfont->imod + zone->mModIdx;
+ mod_end = sfont->imod + (zone+1)->mModIdx;
+ for(;mod != mod_end;mod++)
+ GenModList_insertMod(&gzone, mod);
+
+ zone++;
+ }
+ }
+
+ temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0]));
+ if(!temp)
+ {
+ ERR("Failed reallocating fontsound storage to %ld elements (from %d)\n",
+ (zone_end-zone + *sounds_size), *sounds_size);
+ return;
+ }
+ *sounds = temp;
+ for(;zone != zone_end;zone++)
+ {
+ GenModList lzone = GenModList_clone(&gzone);
+ mod = sfont->imod + zone->mModIdx;
+ mod_end = sfont->imod + (zone+1)->mModIdx;
+ for(;mod != mod_end;mod++)
+ GenModList_insertMod(&lzone, mod);
+
+ gen = sfont->igen + zone->mGenIdx;
+ gen_end = sfont->igen + (zone+1)->mGenIdx;
+ for(;gen != gen_end;gen++)
+ {
+ if(gen->mGenerator == 53)
+ {
+ const SampleHeader *samp;
+ ALfontsound *sound;
+
+ if(gen->mAmount >= sfont->shdr_size-1)
+ {
+ ERR("Generator %ld has invalid sample ID (%d of %d)\n",
+ (long)(gen-sfont->igen), gen->mAmount, sfont->shdr_size-1);
+ break;
+ }
+ samp = &sfont->shdr[gen->mAmount];
+
+ gen = pzone->gens;
+ gen_end = gen + pzone->gens_size;
+ for(;gen != gen_end;gen++)
+ GenModList_accumGen(&lzone, gen);
+
+ mod = pzone->mods;
+ mod_end = mod + pzone->mods_size;
+ for(;mod != mod_end;mod++)
+ GenModList_accumMod(&lzone, mod);
+
+ if(!checkZone(&lzone, preset, inst, samp))
+ break;
+ /* Ignore ROM samples for now. */
+ if((samp->mSampleType&0x8000))
+ break;
+
+ sound = NewFontsound(context);
+ (*sounds)[(*sounds_size)++] = sound;
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_START_SOFT, samp->mStart);
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_END_SOFT, samp->mEnd);
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_START_SOFT, samp->mStartloop);
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_END_SOFT, samp->mEndloop);
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_RATE_SOFT, samp->mSampleRate);
+ ALfontsound_setPropi(sound, context, AL_BASE_KEY_SOFT, (samp->mOriginalKey <= 127) ? samp->mOriginalKey : 60);
+ ALfontsound_setPropi(sound, context, AL_KEY_CORRECTION_SOFT, samp->mCorrection);
+ ALfontsound_setPropi(sound, context, AL_SAMPLE_TYPE_SOFT, getSampleType(samp->mSampleType&0x7fff));
+ fillZone(sound, context, &lzone);
+
+ break;
+ }
+ GenModList_insertGen(&lzone, gen, AL_FALSE);
+ }
+
+ GenModList_Destruct(&lzone);
+ }
+
+ GenModList_Destruct(&gzone);
+}
+
+ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
+{
+ ALsfpreset **presets = NULL;
+ ALsizei presets_size = 0;
+ ALuint ltype;
+ Soundfont sfont;
+ RiffHdr riff;
+ RiffHdr list;
+ ALsizei i;
+
+ Soundfont_Construct(&sfont);
+
+ RiffHdr_read(&riff, stream);
+ if(riff.mCode != FOURCC('R','I','F','F'))
+ ERROR_GOTO(error, "Invalid Format, expected RIFF got '%c%c%c%c'\n", FOURCCARGS(riff.mCode));
+ if((ltype=read_le32(stream)) != FOURCC('s','f','b','k'))
+ ERROR_GOTO(error, "Invalid Format, expected sfbk got '%c%c%c%c'\n", FOURCCARGS(ltype));
+
+ if(READERR(stream) != 0)
+ ERROR_GOTO(error, "Error reading file header\n");
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('L','I','S','T'))
+ ERROR_GOTO(error, "Invalid Format, expected LIST (INFO) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((ltype=read_le32(stream)) != FOURCC('I','N','F','O'))
+ ERROR_GOTO(error, "Invalid Format, expected INFO got '%c%c%c%c'\n", FOURCCARGS(ltype));
+ list.mSize -= 4;
+ while(list.mSize > 0 && !READERR(stream))
+ {
+ RiffHdr info;
+
+ RiffHdr_read(&info, stream);
+ list.mSize -= 8;
+ if(info.mCode == FOURCC('i','f','i','l'))
+ {
+ if(info.mSize != 4)
+ ERR("Invalid ifil chunk size: %d\n", info.mSize);
+ else
+ {
+ ALushort major = read_le16(stream);
+ ALushort minor = read_le16(stream);
+
+ list.mSize -= 4;
+ info.mSize -= 4;
+
+ if(major != 2)
+ ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor);
+ TRACE("SF2 format version: %d.%02d\n", major, minor);
+
+ sfont.ifil = (major<<16) | minor;
+ }
+ }
+ else if(info.mCode == FOURCC('i','r','o','m'))
+ {
+ if(info.mSize == 0 || (info.mSize&1))
+ ERR("Invalid irom size: %d\n", info.mSize);
+ else
+ {
+ free(sfont.irom);
+ sfont.irom = calloc(1, info.mSize+1);
+ READ(stream, sfont.irom, info.mSize);
+
+ list.mSize -= info.mSize;
+ info.mSize -= info.mSize;
+
+ TRACE("SF2 ROM ID: %s\n", sfont.irom);
+ }
+ }
+ list.mSize -= info.mSize;
+ skip(stream, info.mSize);
+ }
+
+ if(READERR(stream) != 0)
+ ERROR_GOTO(error, "Error reading INFO chunk\n");
+ if(sfont.ifil == 0)
+ ERROR_GOTO(error, "Missing ifil sub-chunk\n");
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('L','I','S','T'))
+ ERROR_GOTO(error, "Invalid Format, expected LIST (sdta) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((ltype=read_le32(stream)) != FOURCC('s','d','t','a'))
+ ERROR_GOTO(error, "Invalid Format, expected sdta got '%c%c%c%c'\n", FOURCCARGS(ltype));
+ list.mSize -= 4;
+ {
+ ALbyte *ptr;
+ RiffHdr smpl;
+
+ RiffHdr_read(&smpl, stream);
+ if(smpl.mCode != FOURCC('s','m','p','l'))
+ ERROR_GOTO(error, "Invalid Format, expected smpl got '%c%c%c%c'\n", FOURCCARGS(smpl.mCode));
+ list.mSize -= 8;
+
+ if(smpl.mSize > list.mSize)
+ ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n");
+
+ if(!(ptr=realloc(soundfont->Samples, smpl.mSize)))
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error);
+ soundfont->Samples = (ALshort*)ptr;
+ soundfont->NumSamples = smpl.mSize/2;
+
+ if(IS_LITTLE_ENDIAN)
+ READ(stream, ptr, smpl.mSize);
+ else
+ {
+ while(smpl.mSize > 0)
+ {
+ ALbyte buf[4096];
+ ALuint todo = minu(smpl.mSize, sizeof(buf));
+ ALuint i;
+
+ READ(stream, buf, todo);
+ for(i = 0;i < todo;i++)
+ ptr[i] = buf[i^1];
+ }
+ }
+ list.mSize -= smpl.mSize;
+
+ skip(stream, list.mSize);
+ }
+
+ if(READERR(stream) != 0)
+ ERROR_GOTO(error, "Error reading sdta chunk\n");
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('L','I','S','T'))
+ ERROR_GOTO(error, "Invalid Format, expected LIST (pdta) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((ltype=read_le32(stream)) != FOURCC('p','d','t','a'))
+ ERROR_GOTO(error, "Invalid Format, expected pdta got '%c%c%c%c'\n", FOURCCARGS(ltype));
+
+ //
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('p','h','d','r'))
+ ERROR_GOTO(error, "Invalid Format, expected phdr got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%38) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad phdr size: %u\n", list.mSize);
+ sfont.phdr_size = list.mSize/38;
+ sfont.phdr = calloc(sfont.phdr_size, sizeof(sfont.phdr[0]));
+ for(i = 0;i < sfont.phdr_size;i++)
+ PresetHeader_read(&sfont.phdr[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('p','b','a','g'))
+ ERROR_GOTO(error, "Invalid Format, expected pbag got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%4) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad pbag size: %u\n", list.mSize);
+ sfont.pbag_size = list.mSize/4;
+ sfont.pbag = calloc(sfont.pbag_size, sizeof(sfont.pbag[0]));
+ for(i = 0;i < sfont.pbag_size;i++)
+ Zone_read(&sfont.pbag[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('p','m','o','d'))
+ ERROR_GOTO(error, "Invalid Format, expected pmod got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%10) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad pmod size: %u\n", list.mSize);
+ sfont.pmod_size = list.mSize/10;
+ sfont.pmod = calloc(sfont.pmod_size, sizeof(sfont.pmod[0]));
+ for(i = 0;i < sfont.pmod_size;i++)
+ Modulator_read(&sfont.pmod[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('p','g','e','n'))
+ ERROR_GOTO(error, "Invalid Format, expected pgen got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%4) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad pgen size: %u\n", list.mSize);
+ sfont.pgen_size = list.mSize/4;
+ sfont.pgen = calloc(sfont.pgen_size, sizeof(sfont.pgen[0]));
+ for(i = 0;i < sfont.pgen_size;i++)
+ Generator_read(&sfont.pgen[i], stream);
+
+ //
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('i','n','s','t'))
+ ERROR_GOTO(error, "Invalid Format, expected inst got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%22) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad inst size: %u\n", list.mSize);
+ sfont.inst_size = list.mSize/22;
+ sfont.inst = calloc(sfont.inst_size, sizeof(sfont.inst[0]));
+ for(i = 0;i < sfont.inst_size;i++)
+ InstrumentHeader_read(&sfont.inst[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('i','b','a','g'))
+ ERROR_GOTO(error, "Invalid Format, expected ibag got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%4) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad ibag size: %u\n", list.mSize);
+ sfont.ibag_size = list.mSize/4;
+ sfont.ibag = calloc(sfont.ibag_size, sizeof(sfont.ibag[0]));
+ for(i = 0;i < sfont.ibag_size;i++)
+ Zone_read(&sfont.ibag[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('i','m','o','d'))
+ ERROR_GOTO(error, "Invalid Format, expected imod got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%10) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad imod size: %u\n", list.mSize);
+ sfont.imod_size = list.mSize/10;
+ sfont.imod = calloc(sfont.imod_size, sizeof(sfont.imod[0]));
+ for(i = 0;i < sfont.imod_size;i++)
+ Modulator_read(&sfont.imod[i], stream);
+
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('i','g','e','n'))
+ ERROR_GOTO(error, "Invalid Format, expected igen got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%4) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad igen size: %u\n", list.mSize);
+ sfont.igen_size = list.mSize/4;
+ sfont.igen = calloc(sfont.igen_size, sizeof(sfont.igen[0]));
+ for(i = 0;i < sfont.igen_size;i++)
+ Generator_read(&sfont.igen[i], stream);
+
+ //
+ RiffHdr_read(&list, stream);
+ if(list.mCode != FOURCC('s','h','d','r'))
+ ERROR_GOTO(error, "Invalid Format, expected shdr got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
+ if((list.mSize%46) != 0 || list.mSize == 0)
+ ERROR_GOTO(error, "Invalid Format, bad shdr size: %u\n", list.mSize);
+ sfont.shdr_size = list.mSize/46;
+ sfont.shdr = calloc(sfont.shdr_size, sizeof(sfont.shdr[0]));
+ for(i = 0;i < sfont.shdr_size;i++)
+ SampleHeader_read(&sfont.shdr[i], stream);
+
+ if(READERR(stream) != 0)
+ ERROR_GOTO(error, "Error reading pdta chunk\n");
+
+ if(!ensureFontSanity(&sfont))
+ goto error;
+
+ presets = calloc(1, (sfont.phdr_size-1)*sizeof(presets[0]));
+ if(!presets)
+ ERROR_GOTO(error, "Error allocating presets\n");
+
+ for(i = 0;i < sfont.phdr_size-1;i++)
+ {
+ const Generator *gen, *gen_end;
+ const Modulator *mod, *mod_end;
+ const Zone *zone, *zone_end;
+ ALfontsound **sounds = NULL;
+ ALsizei sounds_size = 0;
+ GenModList gzone;
+
+ if(sfont.phdr[i+1].mZoneIdx == sfont.phdr[i].mZoneIdx)
+ continue;
+
+ GenModList_Construct(&gzone);
+ zone = sfont.pbag + sfont.phdr[i].mZoneIdx;
+ zone_end = sfont.pbag + sfont.phdr[i+1].mZoneIdx;
+ if(zone_end-zone > 1)
+ {
+ gen = sfont.pgen + zone->mGenIdx;
+ gen_end = sfont.pgen + (zone+1)->mGenIdx;
+
+ // If no generators, or last generator is not an instrument, this is a global zone
+ for(;gen != gen_end;gen++)
+ {
+ if(gen->mGenerator == 41)
+ break;
+ }
+
+ if(gen == gen_end)
+ {
+ gen = sfont.pgen + zone->mGenIdx;
+ gen_end = sfont.pgen + (zone+1)->mGenIdx;
+ for(;gen != gen_end;gen++)
+ GenModList_insertGen(&gzone, gen, AL_TRUE);
+
+ mod = sfont.pmod + zone->mModIdx;
+ mod_end = sfont.pmod + (zone+1)->mModIdx;
+ for(;mod != mod_end;mod++)
+ GenModList_insertMod(&gzone, mod);
+
+ zone++;
+ }
+ }
+
+ for(;zone != zone_end;zone++)
+ {
+ GenModList lzone = GenModList_clone(&gzone);
+
+ mod = sfont.pmod + zone->mModIdx;
+ mod_end = sfont.pmod + (zone+1)->mModIdx;
+ for(;mod != mod_end;mod++)
+ GenModList_insertMod(&lzone, mod);
+
+ gen = sfont.pgen + zone->mGenIdx;
+ gen_end = sfont.pgen + (zone+1)->mGenIdx;
+ for(;gen != gen_end;gen++)
+ {
+ if(gen->mGenerator == 41)
+ {
+ if(gen->mAmount >= sfont.inst_size-1)
+ ERR("Generator %ld has invalid instrument ID (%d of %d)\n",
+ (long)(gen-sfont.pgen), gen->mAmount, sfont.inst_size-1);
+ else
+ processInstrument(&sounds, &sounds_size, context,
+ &sfont.inst[gen->mAmount], &sfont.phdr[i], &sfont, &lzone);
+ break;
+ }
+ GenModList_insertGen(&lzone, gen, AL_TRUE);
+ }
+ GenModList_Destruct(&lzone);
+ }
+
+ if(sounds_size > 0)
+ {
+ ALsizei j;
+
+ presets[presets_size] = NewPreset(context);
+ presets[presets_size]->Preset = sfont.phdr[i].mPreset;
+ presets[presets_size]->Bank = sfont.phdr[i].mBank;
+
+ for(j = 0;j < sounds_size;j++)
+ IncrementRef(&sounds[j]->ref);
+ sounds = ExchangePtr((XchgPtr*)&presets[presets_size]->Sounds, sounds);
+ ExchangeInt(&presets[presets_size]->NumSounds, sounds_size);
+ presets_size++;
+ }
+ free(sounds);
+
+ GenModList_Destruct(&gzone);
+ }
+
+ for(i = 0;i < presets_size;i++)
+ IncrementRef(&presets[i]->ref);
+ presets = ExchangePtr((XchgPtr*)&soundfont->Presets, presets);
+ ExchangeInt(&soundfont->NumPresets, presets_size);
+
+ free(presets);
+
+ Soundfont_Destruct(&sfont);
+
+ return AL_TRUE;
+
+error:
+ if(presets)
+ {
+ ALCdevice *device = context->Device;
+ for(i = 0;i < presets_size;i++)
+ DeletePreset(presets[i], device);
+ free(presets);
+ }
+
+ Soundfont_Destruct(&sfont);
+
+ return AL_FALSE;
+}
diff --git a/Alc/mixer.c b/Alc/mixer.c
index f75a7803..acd6c610 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -37,13 +37,13 @@
#include "bs2b.h"
-static __inline ALfloat Sample_ALbyte(ALbyte val)
+static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/127.0f); }
-static __inline ALfloat Sample_ALshort(ALshort val)
+static inline ALfloat Sample_ALshort(ALshort val)
{ return val * (1.0f/32767.0f); }
-static __inline ALfloat Sample_ALfloat(ALfloat val)
+static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
@@ -84,13 +84,13 @@ static void SilenceData(ALfloat *dst, ALuint samples)
}
-static void Filter2P(FILTER *filter, ALuint chan, ALfloat *RESTRICT dst,
- const ALfloat *RESTRICT src, ALuint numsamples)
+static void DoFilter(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src,
+ ALuint numsamples)
{
ALuint i;
for(i = 0;i < numsamples;i++)
- dst[i] = lpFilter2P(filter, chan, src[i]);
- dst[i] = lpFilter2PC(filter, chan, src[i]);
+ dst[i] = ALfilterState_processSingle(filter, src[i]);
+ dst[i] = ALfilterState_processSingleC(filter, src[i]);
}
@@ -131,7 +131,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
const ALuint BufferPadding = ResamplerPadding[Resampler];
ALuint SrcBufferSize, DstBufferSize;
- /* Figure out how many buffer bytes will be needed */
+ /* Figure out how many buffer samples will be needed */
DataSize64 = SamplesToDo-OutPos+1;
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
@@ -328,7 +328,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
{
DirectParams *directparms = &Source->Params.Direct;
- Filter2P(&directparms->iirFilter, chan, SrcData, ResampledData,
+ DoFilter(&directparms->LpFilter[chan], SrcData, ResampledData,
DstBufferSize);
Source->Params.DryMix(directparms, SrcData, chan, OutPos,
SamplesToDo, DstBufferSize);
@@ -337,10 +337,10 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
for(j = 0;j < Device->NumAuxSends;j++)
{
SendParams *sendparms = &Source->Params.Send[j];
- if(!sendparms->Slot)
+ if(!sendparms->OutBuffer)
continue;
- Filter2P(&sendparms->iirFilter, chan, SrcData, ResampledData,
+ DoFilter(&sendparms->LpFilter[chan], SrcData, ResampledData,
DstBufferSize);
Source->Params.WetMix(sendparms, SrcData, OutPos,
SamplesToDo, DstBufferSize);
diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c
index d9c8ca25..36d8bf5a 100644
--- a/Alc/mixer_c.c
+++ b/Alc/mixer_c.c
@@ -8,24 +8,23 @@
#include "alAuxEffectSlot.h"
-static __inline ALfloat point32(const ALfloat *vals, ALuint frac)
-{ return vals[0]; (void)frac; }
-static __inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
+static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac))
+{ return vals[0]; }
+static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
-static __inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
+static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
-void Resample_copy32_C(const ALfloat *data, ALuint frac,
- ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize)
+void Resample_copy32_C(const ALfloat *data, ALuint UNUSED(frac),
+ ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize)
{
- (void)frac;
assert(increment==FRACTIONONE);
memcpy(OutBuffer, data, (BufferSize+1)*sizeof(ALfloat));
}
#define DECL_TEMPLATE(Sampler) \
void Resample_##Sampler##_C(const ALfloat *data, ALuint frac, \
- ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize) \
+ ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize) \
{ \
ALuint pos = 0; \
ALuint i; \
@@ -47,27 +46,22 @@ DECL_TEMPLATE(cubic32)
#undef DECL_TEMPLATE
-static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- const ALfloat (*RESTRICT CoeffStep)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffsStep(const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ const ALfloat (*restrict CoeffStep)[2])
{
ALuint c;
for(c = 0;c < IrSize;c++)
{
- const ALuint off = (Offset+c)&HRIR_MASK;
- Values[off][0] += Coeffs[c][0] * left;
- Values[off][1] += Coeffs[c][1] * right;
Coeffs[c][0] += CoeffStep[c][0];
Coeffs[c][1] += CoeffStep[c][1];
}
}
-static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ ALfloat left, ALfloat right)
{
ALuint c;
for(c = 0;c < IrSize;c++)
@@ -83,12 +77,12 @@ static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
#undef SUFFIX
-void MixDirect_C(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan,
+void MixDirect_C(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
- ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *RESTRICT ClickRemoval = params->ClickRemoval;
- ALfloat *RESTRICT PendingClicks = params->PendingClicks;
+ ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
+ ALfloat *restrict ClickRemoval = params->ClickRemoval;
+ ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat DrySend;
ALuint pos;
ALuint c;
@@ -96,36 +90,36 @@ void MixDirect_C(const DirectParams *params, const ALfloat *RESTRICT data, ALuin
for(c = 0;c < MaxChannels;c++)
{
DrySend = params->Gains[srcchan][c];
- if(DrySend < 0.00001f)
+ if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
if(OutPos == 0)
ClickRemoval[c] -= data[0]*DrySend;
for(pos = 0;pos < BufferSize;pos++)
- DryBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
if(OutPos+pos == SamplesToDo)
PendingClicks[c] += data[pos]*DrySend;
}
}
-void MixSend_C(const SendParams *params, const ALfloat *RESTRICT data,
+void MixSend_C(const SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
- ALeffectslot *Slot = params->Slot;
- ALfloat (*RESTRICT WetBuffer)[BUFFERSIZE] = Slot->WetBuffer;
- ALfloat *RESTRICT WetClickRemoval = Slot->ClickRemoval;
- ALfloat *RESTRICT WetPendingClicks = Slot->PendingClicks;
- ALfloat WetSend = params->Gain;
+ ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
+ ALfloat *restrict ClickRemoval = params->ClickRemoval;
+ ALfloat *restrict PendingClicks = params->PendingClicks;
+ ALfloat WetSend;
ALuint pos;
- if(WetSend < 0.00001f)
+ WetSend = params->Gain;
+ if(!(WetSend > GAIN_SILENCE_THRESHOLD))
return;
if(OutPos == 0)
- WetClickRemoval[0] -= data[0] * WetSend;
+ ClickRemoval[0] -= data[0] * WetSend;
for(pos = 0;pos < BufferSize;pos++)
- WetBuffer[0][OutPos+pos] += data[pos] * WetSend;
+ OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
if(OutPos+pos == SamplesToDo)
- WetPendingClicks[0] += data[pos] * WetSend;
+ PendingClicks[0] += data[pos] * WetSend;
}
diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h
index 6d3390c8..5e43af15 100644
--- a/Alc/mixer_defs.h
+++ b/Alc/mixer_defs.h
@@ -9,23 +9,23 @@ struct DirectParams;
struct SendParams;
/* C resamplers */
-void Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen);
-void Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen);
-void Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen);
-void Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen);
+void Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+void Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+void Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+void Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
/* C mixers */
-void MixDirect_Hrtf_C(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint);
-void MixDirect_C(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint);
-void MixSend_C(const struct SendParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_C(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
+void MixDirect_C(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
+void MixSend_C(const struct SendParams*,const ALfloat*restrict,ALuint,ALuint,ALuint);
/* SSE mixers */
-void MixDirect_Hrtf_SSE(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint);
-void MixDirect_SSE(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint);
-void MixSend_SSE(const struct SendParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_SSE(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
+void MixDirect_SSE(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
+void MixSend_SSE(const struct SendParams*,const ALfloat*restrict,ALuint,ALuint,ALuint);
/* Neon mixers */
-void MixDirect_Hrtf_Neon(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint);
+void MixDirect_Hrtf_Neon(const struct DirectParams*,const ALfloat*restrict,ALuint,ALuint,ALuint,ALuint);
#endif /* MIXER_DEFS_H */
diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c
index 97266d40..17be5cde 100644
--- a/Alc/mixer_inc.c
+++ b/Alc/mixer_inc.c
@@ -18,30 +18,28 @@
#define MixDirect_Hrtf MERGE2(MixDirect_Hrtf_,SUFFIX)
-static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint irSize,
- ALfloat (*RESTRICT Coeffs)[2],
- const ALfloat (*RESTRICT CoeffStep)[2],
- ALfloat left, ALfloat right);
-static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint irSize,
- ALfloat (*RESTRICT Coeffs)[2],
- ALfloat left, ALfloat right);
-
-
-void MixDirect_Hrtf(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan,
+static inline void ApplyCoeffsStep(const ALuint irSize,
+ ALfloat (*restrict Coeffs)[2],
+ const ALfloat (*restrict CoeffStep)[2]);
+static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint irSize,
+ ALfloat (*restrict Coeffs)[2],
+ ALfloat left, ALfloat right);
+
+
+void MixDirect_Hrtf(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
- ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *RESTRICT ClickRemoval = params->ClickRemoval;
- ALfloat *RESTRICT PendingClicks = params->PendingClicks;
+ ALfloat (*restrict DryBuffer)[BUFFERSIZE] = params->OutBuffer;
+ ALfloat *restrict ClickRemoval = params->ClickRemoval;
+ ALfloat *restrict PendingClicks = params->PendingClicks;
const ALuint IrSize = params->Hrtf.Params.IrSize;
- const ALint *RESTRICT DelayStep = params->Hrtf.Params.DelayStep;
- const ALfloat (*RESTRICT CoeffStep)[2] = params->Hrtf.Params.CoeffStep;
- const ALfloat (*RESTRICT TargetCoeffs)[2] = params->Hrtf.Params.Coeffs[srcchan];
- const ALuint *RESTRICT TargetDelay = params->Hrtf.Params.Delay[srcchan];
- ALfloat *RESTRICT History = params->Hrtf.State->History[srcchan];
- ALfloat (*RESTRICT Values)[2] = params->Hrtf.State->Values[srcchan];
+ const ALint *restrict DelayStep = params->Hrtf.Params.DelayStep;
+ const ALfloat (*restrict CoeffStep)[2] = params->Hrtf.Params.CoeffStep;
+ const ALfloat (*restrict TargetCoeffs)[2] = params->Hrtf.Params.Coeffs[srcchan];
+ const ALuint *restrict TargetDelay = params->Hrtf.Params.Delay[srcchan];
+ ALfloat *restrict History = params->Hrtf.State->History[srcchan];
+ ALfloat (*restrict Values)[2] = params->Hrtf.State->Values[srcchan];
ALint Counter = maxu(params->Hrtf.State->Counter, OutPos) - OutPos;
ALuint Offset = params->Hrtf.State->Offset + OutPos;
ALIGN(16) ALfloat Coeffs[HRIR_LENGTH][2];
@@ -92,9 +90,10 @@ void MixDirect_Hrtf(const DirectParams *params, const ALfloat *RESTRICT data, AL
Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
- ApplyCoeffsStep(Offset, Values, IrSize, Coeffs, CoeffStep, left, right);
+ ApplyCoeffs(Offset, Values, IrSize, Coeffs, left, right);
DryBuffer[FrontLeft][OutPos] += Values[Offset&HRIR_MASK][0];
DryBuffer[FrontRight][OutPos] += Values[Offset&HRIR_MASK][1];
+ ApplyCoeffsStep(IrSize, Coeffs, CoeffStep);
OutPos++;
Counter--;
diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c
index 23dc792c..571221be 100644
--- a/Alc/mixer_neon.c
+++ b/Alc/mixer_neon.c
@@ -10,27 +10,22 @@
#include "alu.h"
-static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- const ALfloat (*RESTRICT CoeffStep)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffsStep(const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ const ALfloat (*restrict CoeffStep)[2])
{
ALuint c;
for(c = 0;c < IrSize;c++)
{
- const ALuint off = (Offset+c)&HRIR_MASK;
- Values[off][0] += Coeffs[c][0] * left;
- Values[off][1] += Coeffs[c][1] * right;
Coeffs[c][0] += CoeffStep[c][0];
Coeffs[c][1] += CoeffStep[c][1];
}
}
-static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ ALfloat left, ALfloat right)
{
ALuint c;
float32x4_t leftright4;
diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c
index 3c45fd21..719ebd23 100644
--- a/Alc/mixer_sse.c
+++ b/Alc/mixer_sse.c
@@ -1,6 +1,13 @@
#include "config.h"
#ifdef HAVE_XMMINTRIN_H
+#ifdef IN_IDE_PARSER
+/* KDevelop's parser won't recognize these defines that get added by the -msse
+ * switch used to compile this source. Without them, xmmintrin.h fails to
+ * declare anything. */
+#define __MMX__
+#define __SSE__
+#endif
#include <xmmintrin.h>
#endif
@@ -14,72 +21,26 @@
#include "mixer_defs.h"
-static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- const ALfloat (*RESTRICT CoeffStep)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffsStep(const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ const ALfloat (*restrict CoeffStep)[2])
{
- const __m128 lrlr = { left, right, left, right };
- __m128 coeffs, deltas, imp0, imp1;
- __m128 vals = _mm_setzero_ps();
+ __m128 coeffs, deltas;
ALuint i;
- if((Offset&1))
+ for(i = 0;i < IrSize;i += 2)
{
- const ALuint o0 = Offset&HRIR_MASK;
- const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
-
- coeffs = _mm_load_ps(&Coeffs[0][0]);
- deltas = _mm_load_ps(&CoeffStep[0][0]);
- vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
- imp0 = _mm_mul_ps(lrlr, coeffs);
+ coeffs = _mm_load_ps(&Coeffs[i][0]);
+ deltas = _mm_load_ps(&CoeffStep[i][0]);
coeffs = _mm_add_ps(coeffs, deltas);
- vals = _mm_add_ps(imp0, vals);
- _mm_store_ps(&Coeffs[0][0], coeffs);
- _mm_storel_pi((__m64*)&Values[o0][0], vals);
- for(i = 1;i < IrSize-1;i += 2)
- {
- const ALuint o2 = (Offset+i)&HRIR_MASK;
-
- coeffs = _mm_load_ps(&Coeffs[i+1][0]);
- deltas = _mm_load_ps(&CoeffStep[i+1][0]);
- vals = _mm_load_ps(&Values[o2][0]);
- imp1 = _mm_mul_ps(lrlr, coeffs);
- coeffs = _mm_add_ps(coeffs, deltas);
- imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
- vals = _mm_add_ps(imp0, vals);
- _mm_store_ps(&Coeffs[i+1][0], coeffs);
- _mm_store_ps(&Values[o2][0], vals);
- imp0 = imp1;
- }
- vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
- imp0 = _mm_movehl_ps(imp0, imp0);
- vals = _mm_add_ps(imp0, vals);
- _mm_storel_pi((__m64*)&Values[o1][0], vals);
- }
- else
- {
- for(i = 0;i < IrSize;i += 2)
- {
- const ALuint o = (Offset + i)&HRIR_MASK;
-
- coeffs = _mm_load_ps(&Coeffs[i][0]);
- deltas = _mm_load_ps(&CoeffStep[i][0]);
- vals = _mm_load_ps(&Values[o][0]);
- imp0 = _mm_mul_ps(lrlr, coeffs);
- coeffs = _mm_add_ps(coeffs, deltas);
- vals = _mm_add_ps(imp0, vals);
- _mm_store_ps(&Coeffs[i][0], coeffs);
- _mm_store_ps(&Values[o][0], vals);
- }
+ _mm_store_ps(&Coeffs[i][0], coeffs);
}
}
-static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
- const ALuint IrSize,
- ALfloat (*RESTRICT Coeffs)[2],
- ALfloat left, ALfloat right)
+static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
+ const ALuint IrSize,
+ ALfloat (*restrict Coeffs)[2],
+ ALfloat left, ALfloat right)
{
const __m128 lrlr = { left, right, left, right };
__m128 vals = _mm_setzero_ps();
@@ -133,22 +94,21 @@ static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
#undef SUFFIX
-void MixDirect_SSE(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan,
+void MixDirect_SSE(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
- ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer;
- ALfloat *RESTRICT ClickRemoval = params->ClickRemoval;
- ALfloat *RESTRICT PendingClicks = params->PendingClicks;
+ ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
+ ALfloat *restrict ClickRemoval = params->ClickRemoval;
+ ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat DrySend;
+ __m128 gain;
ALuint pos;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- __m128 gain;
-
DrySend = params->Gains[srcchan][c];
- if(DrySend < 0.00001f)
+ if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
if(OutPos == 0)
@@ -158,12 +118,12 @@ void MixDirect_SSE(const DirectParams *params, const ALfloat *RESTRICT data, ALu
for(pos = 0;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
- __m128 dry4 = _mm_load_ps(&DryBuffer[c][OutPos+pos]);
+ __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
- _mm_store_ps(&DryBuffer[c][OutPos+pos], dry4);
+ _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
- DryBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
if(OutPos+pos == SamplesToDo)
PendingClicks[c] += data[pos]*DrySend;
@@ -171,34 +131,34 @@ void MixDirect_SSE(const DirectParams *params, const ALfloat *RESTRICT data, ALu
}
-void MixSend_SSE(const SendParams *params, const ALfloat *RESTRICT data,
+void MixSend_SSE(const SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
- ALeffectslot *Slot = params->Slot;
- ALfloat (*RESTRICT WetBuffer)[BUFFERSIZE] = Slot->WetBuffer;
- ALfloat *RESTRICT WetClickRemoval = Slot->ClickRemoval;
- ALfloat *RESTRICT WetPendingClicks = Slot->PendingClicks;
- const ALfloat WetGain = params->Gain;
+ ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
+ ALfloat *restrict ClickRemoval = params->ClickRemoval;
+ ALfloat *restrict PendingClicks = params->PendingClicks;
+ ALfloat WetGain;
__m128 gain;
ALuint pos;
- if(WetGain < 0.00001f)
+ WetGain = params->Gain;
+ if(!(WetGain > GAIN_SILENCE_THRESHOLD))
return;
if(OutPos == 0)
- WetClickRemoval[0] -= data[0] * WetGain;
+ ClickRemoval[0] -= data[0] * WetGain;
gain = _mm_set1_ps(WetGain);
for(pos = 0;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
- __m128 wet4 = _mm_load_ps(&WetBuffer[0][OutPos+pos]);
+ __m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
- _mm_store_ps(&WetBuffer[0][OutPos+pos], wet4);
+ _mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
}
for(;pos < BufferSize;pos++)
- WetBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
if(OutPos+pos == SamplesToDo)
- WetPendingClicks[0] += data[pos] * WetGain;
+ PendingClicks[0] += data[pos] * WetGain;
}
diff --git a/Alc/panning.c b/Alc/panning.c
index d8191d8d..30a1e571 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -31,6 +31,8 @@
#include "AL/alc.h"
#include "alu.h"
+extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]);
+
static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
enum Channel Speaker2Chan[MaxChannels], ALint chans)
{
@@ -102,7 +104,7 @@ static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChan
{
long angle = strtol(sep, NULL, 10);
if(angle >= -180 && angle <= 180)
- SpeakerAngle[i] = angle * F_PI/180.0f;
+ SpeakerAngle[i] = DEG2RAD(angle);
else
ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
break;
@@ -140,13 +142,7 @@ static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChan
}
-/**
- * ComputeAngleGains
- *
- * Sets channel gains based on a given source's angle and its half-width. The
- * angle and hwidth parameters are in radians.
- */
-ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains)
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels])
{
ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
enum Channel Speaker2Chan[MaxChannels];
@@ -161,9 +157,11 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
SpeakerAngle[i] = device->SpeakerAngle[i];
/* Some easy special-cases first... */
- if(device->NumChan == 1 || hwidth >= F_PI)
+ if(device->NumChan <= 1 || hwidth >= F_PI)
{
/* Full coverage for all speakers. */
+ for(i = 0;i < MaxChannels;i++)
+ gains[i] = 0.0f;
for(i = 0;i < device->NumChan;i++)
{
enum Channel chan = Speaker2Chan[i];
@@ -174,6 +172,8 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
if(hwidth <= 0.0f)
{
/* Infinitely small sound point. */
+ for(i = 0;i < MaxChannels;i++)
+ gains[i] = 0.0f;
for(i = 0;i < device->NumChan-1;i++)
{
if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
@@ -188,9 +188,9 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
}
/* Sound is between last and first speakers */
if(angle < SpeakerAngle[0])
- angle += F_PI*2.0f;
- a = (angle-SpeakerAngle[i]) /
- (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
+ angle += F_2PI;
+ a = (angle-SpeakerAngle[i]) /
+ (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
gains[Speaker2Chan[0]] = sqrtf( a) * ingain;
return;
@@ -203,7 +203,7 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
* within -pi...+pi. */
if(angle > 0.0f)
{
- ALuint done = 0;
+ ALuint done;
ALuint i = 0;
while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
i++;
@@ -215,7 +215,7 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
}
for(i = 0;done < device->NumChan;i++)
{
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_PI*2.0f;
+ SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI;
Speaker2Chan[done] = device->Speaker2Chan[i];
done++;
}
@@ -226,7 +226,7 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
* we need to handle index 0. Because the iterators are unsigned,
* they'll underflow and wrap to become 0xFFFFFFFF, which will
* break as expected. */
- ALuint done = device->NumChan-1;
+ ALuint done;
ALuint i = device->NumChan-1;
while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI)
i--;
@@ -238,7 +238,7 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
}
for(i = device->NumChan-1;done < device->NumChan;i--)
{
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_PI*2.0f;
+ SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI;
Speaker2Chan[done] = device->Speaker2Chan[i];
done--;
}
@@ -268,14 +268,14 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
}
if(SpeakerAngle[i] > rangle)
{
- a = (F_PI*2.0f + rangle-SpeakerAngle[last]) /
- (F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
+ a = (F_2PI + rangle-SpeakerAngle[last]) /
+ (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
else if(SpeakerAngle[last] < rangle)
{
- a = (rangle-SpeakerAngle[last]) /
- (F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
+ a = (rangle-SpeakerAngle[last]) /
+ (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
} while(0);
@@ -320,14 +320,14 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
}
if(SpeakerAngle[i] < langle)
{
- a = (langle-SpeakerAngle[i]) /
- (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
+ a = (langle-SpeakerAngle[i]) /
+ (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
else if(SpeakerAngle[0] > langle)
{
- a = (F_PI*2.0f + langle-SpeakerAngle[i]) /
- (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
+ a = (F_2PI + langle-SpeakerAngle[i]) /
+ (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
} while(0);
@@ -353,7 +353,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
case DevFmtMono:
Device->NumChan = 1;
Speaker2Chan[0] = FrontCenter;
- SpeakerAngle[0] = F_PI/180.0f * 0.0f;
+ SpeakerAngle[0] = DEG2RAD(0.0f);
layoutname = NULL;
break;
@@ -361,8 +361,8 @@ ALvoid aluInitPanning(ALCdevice *Device)
Device->NumChan = 2;
Speaker2Chan[0] = FrontLeft;
Speaker2Chan[1] = FrontRight;
- SpeakerAngle[0] = F_PI/180.0f * -90.0f;
- SpeakerAngle[1] = F_PI/180.0f * 90.0f;
+ SpeakerAngle[0] = DEG2RAD(-90.0f);
+ SpeakerAngle[1] = DEG2RAD( 90.0f);
layoutname = "layout_stereo";
break;
@@ -372,10 +372,10 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[1] = FrontLeft;
Speaker2Chan[2] = FrontRight;
Speaker2Chan[3] = BackRight;
- SpeakerAngle[0] = F_PI/180.0f * -135.0f;
- SpeakerAngle[1] = F_PI/180.0f * -45.0f;
- SpeakerAngle[2] = F_PI/180.0f * 45.0f;
- SpeakerAngle[3] = F_PI/180.0f * 135.0f;
+ SpeakerAngle[0] = DEG2RAD(-135.0f);
+ SpeakerAngle[1] = DEG2RAD( -45.0f);
+ SpeakerAngle[2] = DEG2RAD( 45.0f);
+ SpeakerAngle[3] = DEG2RAD( 135.0f);
layoutname = "layout_quad";
break;
@@ -386,11 +386,11 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[2] = FrontCenter;
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = BackRight;
- SpeakerAngle[0] = F_PI/180.0f * -110.0f;
- SpeakerAngle[1] = F_PI/180.0f * -30.0f;
- SpeakerAngle[2] = F_PI/180.0f * 0.0f;
- SpeakerAngle[3] = F_PI/180.0f * 30.0f;
- SpeakerAngle[4] = F_PI/180.0f * 110.0f;
+ SpeakerAngle[0] = DEG2RAD(-110.0f);
+ SpeakerAngle[1] = DEG2RAD( -30.0f);
+ SpeakerAngle[2] = DEG2RAD( 0.0f);
+ SpeakerAngle[3] = DEG2RAD( 30.0f);
+ SpeakerAngle[4] = DEG2RAD( 110.0f);
layoutname = "layout_surround51";
break;
@@ -401,11 +401,11 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[2] = FrontCenter;
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = SideRight;
- SpeakerAngle[0] = F_PI/180.0f * -90.0f;
- SpeakerAngle[1] = F_PI/180.0f * -30.0f;
- SpeakerAngle[2] = F_PI/180.0f * 0.0f;
- SpeakerAngle[3] = F_PI/180.0f * 30.0f;
- SpeakerAngle[4] = F_PI/180.0f * 90.0f;
+ SpeakerAngle[0] = DEG2RAD(-90.0f);
+ SpeakerAngle[1] = DEG2RAD(-30.0f);
+ SpeakerAngle[2] = DEG2RAD( 0.0f);
+ SpeakerAngle[3] = DEG2RAD( 30.0f);
+ SpeakerAngle[4] = DEG2RAD( 90.0f);
layoutname = "layout_side51";
break;
@@ -417,12 +417,12 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = SideRight;
Speaker2Chan[5] = BackCenter;
- SpeakerAngle[0] = F_PI/180.0f * -90.0f;
- SpeakerAngle[1] = F_PI/180.0f * -30.0f;
- SpeakerAngle[2] = F_PI/180.0f * 0.0f;
- SpeakerAngle[3] = F_PI/180.0f * 30.0f;
- SpeakerAngle[4] = F_PI/180.0f * 90.0f;
- SpeakerAngle[5] = F_PI/180.0f * 180.0f;
+ SpeakerAngle[0] = DEG2RAD(-90.0f);
+ SpeakerAngle[1] = DEG2RAD(-30.0f);
+ SpeakerAngle[2] = DEG2RAD( 0.0f);
+ SpeakerAngle[3] = DEG2RAD( 30.0f);
+ SpeakerAngle[4] = DEG2RAD( 90.0f);
+ SpeakerAngle[5] = DEG2RAD(180.0f);
layoutname = "layout_surround61";
break;
@@ -435,13 +435,13 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[4] = FrontRight;
Speaker2Chan[5] = SideRight;
Speaker2Chan[6] = BackRight;
- SpeakerAngle[0] = F_PI/180.0f * -150.0f;
- SpeakerAngle[1] = F_PI/180.0f * -90.0f;
- SpeakerAngle[2] = F_PI/180.0f * -30.0f;
- SpeakerAngle[3] = F_PI/180.0f * 0.0f;
- SpeakerAngle[4] = F_PI/180.0f * 30.0f;
- SpeakerAngle[5] = F_PI/180.0f * 90.0f;
- SpeakerAngle[6] = F_PI/180.0f * 150.0f;
+ SpeakerAngle[0] = DEG2RAD(-150.0f);
+ SpeakerAngle[1] = DEG2RAD( -90.0f);
+ SpeakerAngle[2] = DEG2RAD( -30.0f);
+ SpeakerAngle[3] = DEG2RAD( 0.0f);
+ SpeakerAngle[4] = DEG2RAD( 30.0f);
+ SpeakerAngle[5] = DEG2RAD( 90.0f);
+ SpeakerAngle[6] = DEG2RAD( 150.0f);
layoutname = "layout_surround71";
break;
}
diff --git a/Alc/rwlock.h b/Alc/rwlock.h
new file mode 100644
index 00000000..efbab4e8
--- /dev/null
+++ b/Alc/rwlock.h
@@ -0,0 +1,21 @@
+#ifndef AL_RWLOCK_H
+#define AL_RWLOCK_H
+
+#include "AL/al.h"
+#include "atomic.h"
+
+typedef struct {
+ volatile RefCount read_count;
+ volatile RefCount write_count;
+ volatile ALenum read_lock;
+ volatile ALenum read_entry_lock;
+ volatile ALenum write_lock;
+} RWLock;
+
+void RWLockInit(RWLock *lock);
+void ReadLock(RWLock *lock);
+void ReadUnlock(RWLock *lock);
+void WriteLock(RWLock *lock);
+void WriteUnlock(RWLock *lock);
+
+#endif /* AL_RWLOCK_H */
diff --git a/Alc/threads.c b/Alc/threads.c
new file mode 100644
index 00000000..64586ae9
--- /dev/null
+++ b/Alc/threads.c
@@ -0,0 +1,200 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "threads.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "alMain.h"
+#include "alThunk.h"
+
+#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct althread_info {
+ ALuint (*func)(ALvoid*);
+ ALvoid *ptr;
+ HANDLE hdl;
+} althread_info;
+
+static DWORD CALLBACK StarterFunc(void *ptr)
+{
+ althread_info *inf = (althread_info*)ptr;
+ ALuint ret;
+
+ ret = inf->func(inf->ptr);
+ ExitThread((DWORD)ret);
+
+ return (DWORD)ret;
+}
+
+
+ALboolean StartThread(althread_t *thread, ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+ althread_info *info;
+ DWORD dummy;
+
+ info = malloc(sizeof(*info));
+ if(!info) return AL_FALSE;
+
+ info->func = func;
+ info->ptr = ptr;
+
+ info->hdl = CreateThread(NULL, THREAD_STACK_SIZE, StarterFunc, info, 0, &dummy);
+ if(!info->hdl)
+ {
+ free(info);
+ return AL_FALSE;
+ }
+
+ *thread = info;
+ return AL_TRUE;
+}
+
+ALuint StopThread(althread_t thread)
+{
+ DWORD ret = 0;
+
+ WaitForSingleObject(thread->hdl, INFINITE);
+ GetExitCodeThread(thread->hdl, &ret);
+ CloseHandle(thread->hdl);
+
+ free(thread);
+
+ return (ALuint)ret;
+}
+
+
+void SetThreadName(const char *name)
+{
+#if defined(_MSC_VER)
+#define MS_VC_EXCEPTION 0x406D1388
+ struct {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+ } info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = -1;
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
+ }
+ __except(EXCEPTION_CONTINUE_EXECUTION) {
+ }
+#undef MS_VC_EXCEPTION
+#else
+ TRACE("Can't set thread %04lx name to \"%s\"\n", GetCurrentThreadId(), name);
+#endif
+}
+
+#else
+
+#include <pthread.h>
+
+typedef struct althread_info {
+ ALuint (*func)(ALvoid*);
+ ALvoid *ptr;
+ ALuint ret;
+ pthread_t hdl;
+} althread_info;
+
+static void *StarterFunc(void *ptr)
+{
+ althread_info *inf = (althread_info*)ptr;
+ inf->ret = inf->func(inf->ptr);
+ return NULL;
+}
+
+
+ALboolean StartThread(althread_t *thread, ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+ pthread_attr_t attr;
+ althread_info *info;
+
+ info = malloc(sizeof(*info));
+ if(!info) return AL_FALSE;
+
+ if(pthread_attr_init(&attr) != 0)
+ {
+ free(info);
+ return AL_FALSE;
+ }
+ if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0)
+ {
+ pthread_attr_destroy(&attr);
+ free(info);
+ return AL_FALSE;
+ }
+
+ info->func = func;
+ info->ptr = ptr;
+ if(pthread_create(&info->hdl, &attr, StarterFunc, info) != 0)
+ {
+ pthread_attr_destroy(&attr);
+ free(info);
+ return AL_FALSE;
+ }
+ pthread_attr_destroy(&attr);
+
+ *thread = info;
+ return AL_TRUE;
+}
+
+ALuint StopThread(althread_t thread)
+{
+ ALuint ret;
+
+ pthread_join(thread->hdl, NULL);
+ ret = thread->ret;
+
+ free(thread);
+
+ return ret;
+}
+
+
+void SetThreadName(const char *name)
+{
+#if defined(HAVE_PTHREAD_SETNAME_NP)
+#if defined(__GNUC__)
+ if(pthread_setname_np(pthread_self(), name) != 0)
+#elif defined(__APPLE__)
+ if(pthread_setname_np(name) != 0)
+#endif
+ WARN("Failed to set thread name to \"%s\": %s\n", name, strerror(errno));
+#elif defined(HAVE_PTHREAD_SET_NAME_NP)
+ pthread_set_name_np(pthread_self(), name);
+#else
+ TRACE("Can't set thread name to \"%s\"\n", name);
+#endif
+}
+
+#endif
diff --git a/Alc/uintmap.h b/Alc/uintmap.h
new file mode 100644
index 00000000..2c70f161
--- /dev/null
+++ b/Alc/uintmap.h
@@ -0,0 +1,34 @@
+#ifndef AL_UINTMAP_H
+#define AL_UINTMAP_H
+
+#include "AL/al.h"
+#include "rwlock.h"
+
+typedef struct UIntMap {
+ struct {
+ ALuint key;
+ ALvoid *value;
+ } *array;
+ ALsizei size;
+ ALsizei maxsize;
+ ALsizei limit;
+ RWLock lock;
+} UIntMap;
+extern UIntMap TlsDestructor;
+
+void InitUIntMap(UIntMap *map, ALsizei limit);
+void ResetUIntMap(UIntMap *map);
+ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
+ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key);
+ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
+
+inline void LockUIntMapRead(UIntMap *map)
+{ ReadLock(&map->lock); }
+inline void UnlockUIntMapRead(UIntMap *map)
+{ ReadUnlock(&map->lock); }
+inline void LockUIntMapWrite(UIntMap *map)
+{ WriteLock(&map->lock); }
+inline void UnlockUIntMapWrite(UIntMap *map)
+{ WriteUnlock(&map->lock); }
+
+#endif /* AL_UINTMAP_H */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d005432..ff746764 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,15 @@
# CMake build file list for OpenAL
-CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(OpenAL)
IF(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET CMP0003 NEW)
+ CMAKE_POLICY(SET CMP0005 NEW)
ENDIF(COMMAND CMAKE_POLICY)
-SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake")
INCLUDE(CheckFunctionExists)
INCLUDE(CheckLibraryExists)
@@ -17,39 +20,46 @@ INCLUDE(CheckSymbolExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckTypeSize)
-INCLUDE(FindPkgConfig)
-
-
-PROJECT(OpenAL C)
SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
-OPTION(ALSOFT_CPUEXT_SSE "Check for SSE CPU extensions" ON)
-OPTION(ALSOFT_CPUEXT_NEON "Check for ARM Neon CPU extensions" ON)
+OPTION(ALSOFT_CPUEXT_SSE "Check for SSE/SSE2 support" ON)
+OPTION(ALSOFT_CPUEXT_NEON "Check for ARM Neon support" ON)
-OPTION(ALSOFT_REQUIRE_SSE "Require SSE CPU extensions" OFF)
-OPTION(ALSOFT_REQUIRE_NEON "Require ARM Neon CPU extensions" OFF)
+OPTION(ALSOFT_REQUIRE_SSE "Require SSE/SSE2 support" OFF)
+OPTION(ALSOFT_REQUIRE_NEON "Require ARM Neon support" OFF)
+
+IF(WIN32)
+ # This option is mainly for static linking OpenAL Soft into another project
+ # that already defines the IDs. It is up to that project to ensure all
+ # required IDs are defined.
+ OPTION(ALSOFT_NO_UID_DEFS "Do not define GUIDs, IIDs, CLSIDs, or PropertyKeys" OFF)
+ENDIF()
OPTION(ALSOFT_BACKEND_ALSA "Check for ALSA backend" ON)
OPTION(ALSOFT_BACKEND_OSS "Check for OSS backend" ON)
OPTION(ALSOFT_BACKEND_SOLARIS "Check for Solaris backend" ON)
OPTION(ALSOFT_BACKEND_SNDIO "Check for SndIO backend" ON)
-OPTION(ALSOFT_BACKEND_MMDEVAPI "Check for MMDevApi" ON)
-OPTION(ALSOFT_BACKEND_DSOUND "Check for DirectSound backend" ON)
-OPTION(ALSOFT_BACKEND_WINMM "Check for Windows Multimedia backend" ON)
+OPTION(ALSOFT_BACKEND_QSA "Check for QSA backend" ON)
+OPTION(ALSOFT_BACKEND_MMDEVAPI "Check for MMDevApi backend" ON)
+OPTION(ALSOFT_BACKEND_DSOUND "Check for DirectSound backend" ON)
+OPTION(ALSOFT_BACKEND_WINMM "Check for Windows Multimedia backend" ON)
OPTION(ALSOFT_BACKEND_PORTAUDIO "Check for PortAudio backend" ON)
OPTION(ALSOFT_BACKEND_PULSEAUDIO "Check for PulseAudio backend" ON)
OPTION(ALSOFT_BACKEND_COREAUDIO "Check for CoreAudio backend" ON)
OPTION(ALSOFT_BACKEND_OPENSL "Check for OpenSL backend" ON)
-OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON)
+OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON)
+
+OPTION(ALSOFT_MIDI_FLUIDSYNTH "Check for FluidSynth MIDI" ON)
OPTION(ALSOFT_REQUIRE_ALSA "Require ALSA backend" OFF)
OPTION(ALSOFT_REQUIRE_OSS "Require OSS backend" OFF)
OPTION(ALSOFT_REQUIRE_SOLARIS "Require Solaris backend" OFF)
OPTION(ALSOFT_REQUIRE_SNDIO "Require SndIO backend" OFF)
+OPTION(ALSOFT_REQUIRE_QSA "Require QSA backend" OFF)
OPTION(ALSOFT_REQUIRE_MMDEVAPI "Require MMDevApi" OFF)
OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF)
OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF)
@@ -58,11 +68,14 @@ OPTION(ALSOFT_REQUIRE_PULSEAUDIO "Require PulseAudio backend" OFF)
OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF)
OPTION(ALSOFT_REQUIRE_OPENSL "Require OpenSL backend" OFF)
+OPTION(ALSOFT_REQUIRE_FLUIDSYNTH "Require FluidSynth MIDI" OFF)
+
OPTION(ALSOFT_DLOPEN "Check for the dlopen API for loading optional libs" ON)
OPTION(ALSOFT_WERROR "Treat compile warnings as errors" OFF)
-OPTION(ALSOFT_UTILS "Build and install utility programs" ON)
+OPTION(ALSOFT_UTILS "Build and install utility programs" ON)
+OPTION(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF)
OPTION(ALSOFT_EXAMPLES "Build and install example programs" ON)
@@ -76,6 +89,12 @@ ELSE()
SET(LIBNAME openal)
ENDIF()
+# QNX's gcc do not uses /usr/include and /usr/lib pathes by default
+IF ("${CMAKE_C_PLATFORM_ID}" STREQUAL "QNX")
+ ADD_DEFINITIONS("-I/usr/include")
+ SET(EXTRA_LIBS ${EXTRA_LIBS} -L/usr/lib)
+ENDIF()
+
IF(NOT LIBTYPE)
SET(LIBTYPE SHARED)
ENDIF()
@@ -87,28 +106,77 @@ SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
SET(EXPORT_DECL "")
SET(ALIGN_DECL "")
-SET(RESTRICT_DECL "")
CHECK_TYPE_SIZE("long" SIZEOF_LONG)
CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
-CHECK_C_SOURCE_COMPILES("int *restrict foo;
- int main() {return 0;}" HAVE_RESTRICT)
-IF(HAVE_RESTRICT)
- SET(RESTRICT_DECL "restrict")
-ELSE()
- CHECK_C_SOURCE_COMPILES("int *__restrict foo;
- int main() {return 0;}" HAVE___RESTRICT)
- IF(HAVE___RESTRICT)
- SET(RESTRICT_DECL "__restrict")
+CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
+IF(HAVE_STD_C99)
+ SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+ENDIF()
+
+# MSVC may need workarounds for C99 restrict and inline
+IF(MSVC)
+ # TODO: Once we truly require C99, these restrict and inline checks should go
+ # away.
+ CHECK_C_SOURCE_COMPILES("int *restrict foo;
+ int main() {return 0;}" HAVE_RESTRICT)
+ IF(NOT HAVE_RESTRICT)
+ # Slightly convoluted way to do this, because MSVC may barf if restrict is
+ # defined to __restrict.
+ CHECK_C_SOURCE_COMPILES("#define restrict __restrict
+ #include <stdlib.h>
+ int *restrict foo;
+ int main() {return 0;}" HAVE___RESTRICT)
+ IF(HAVE___RESTRICT)
+ ADD_DEFINITIONS(-Drestrict=__restrict)
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Drestrict=__restrict")
+ ELSE()
+ ADD_DEFINITIONS("-Drestrict=")
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Drestrict=")
+ ENDIF()
+ ENDIF()
+
+ CHECK_C_SOURCE_COMPILES("inline void foo(void) { }
+ int main() {return 0;}" HAVE_INLINE)
+ IF(NOT HAVE_INLINE)
+ CHECK_C_SOURCE_COMPILES("__inline void foo(void) { }
+ int main() {return 0;}" HAVE___INLINE)
+ IF(NOT HAVE___INLINE)
+ MESSAGE(FATAL_ERROR "No inline keyword found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Dinline=__inline)
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Dinline=__inline")
ENDIF()
ENDIF()
+# Make sure we have C99-style inline semantics with GCC (4.3 or newer).
+IF(CMAKE_COMPILER_IS_GNUCC)
+ SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+ # Force no inlining for the next test.
+ SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -fno-inline")
+
+ CHECK_C_SOURCE_COMPILES("extern inline int foo() { return 0; }
+ int main() {return foo();}" INLINE_IS_C99)
+ IF(NOT INLINE_IS_C99)
+ MESSAGE(FATAL_ERROR "Your compiler does not seem to have C99 inline semantics!
+ Please update your compiler for better C99 compliance.")
+ ENDIF()
+
+ SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}")
+ENDIF()
# Add definitions, compiler switches, etc.
-INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}")
+INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_BINARY_DIR}")
+IF(CMAKE_VERSION VERSION_LESS "2.8.8")
+ INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
+ IF(WIN32 AND ALSOFT_NO_UID_DEFS)
+ ADD_DEFINITIONS("-DAL_NO_UID_DEFS")
+ ENDIF()
+ENDIF()
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
@@ -129,6 +197,7 @@ IF(MSVC)
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
+ ADD_DEFINITIONS("/wd4098")
IF(NOT DXSDK_DIR)
STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}")
@@ -183,22 +252,10 @@ ENDIF()
# Set visibility/export options if available
IF(WIN32)
SET(EXPORT_DECL "__declspec(dllexport)")
- SET(ALIGN_DECL "__declspec(align(x))")
-
- OPTION(WINE "Enable use of Wine headers when compiling" OFF)
- IF(WINE)
- FIND_PATH(WINE_INCLUDE_DIR library.h
- PATHS
- /usr/include/wine
- /usr/local/include/wine
- CMAKE_FIND_ROOT_PATH_BOTH)
- IF(WINE_INCLUDE_DIR)
- MESSAGE(STATUS "Found Wine header files - ${WINE_INCLUDE_DIR}" )
- INCLUDE_DIRECTORIES("${WINE_INCLUDE_DIR}/windows")
- SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${WINE_INCLUDE_DIR}/windows")
- ELSE()
- MESSAGE(STATUS "Could not find Wine header files" )
- ENDIF()
+ IF(NOT MINGW)
+ SET(ALIGN_DECL "__declspec(align(x))")
+ ELSE()
+ SET(ALIGN_DECL "__declspec(aligned(x))")
ENDIF()
ELSE()
SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
@@ -256,7 +313,9 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri
int main() {return 0;}" HAVE_GCC_FORMAT)
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
+CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H)
+CHECK_INCLUDE_FILE(sys/sysconf.h HAVE_SYS_SYSCONF_H)
CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
CHECK_INCLUDE_FILE(ieeefp.h HAVE_IEEEFP_H)
@@ -278,9 +337,6 @@ CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC)
CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF)
-IF(HAVE_FENV_H)
- CHECK_SYMBOL_EXISTS(fesetround fenv.h HAVE_FESETROUND)
-ENDIF()
IF(HAVE_FLOAT_H)
CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP)
CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2)
@@ -318,16 +374,6 @@ IF(NOT HAVE_SNPRINTF)
ADD_DEFINITIONS(-Dsnprintf=_snprintf)
ENDIF()
-CHECK_FUNCTION_EXISTS(vsnprintf HAVE_VSNPRINTF)
-IF(NOT HAVE_VSNPRINTF)
- CHECK_FUNCTION_EXISTS(_vsnprintf HAVE__VSNPRINTF)
- IF(NOT HAVE__VSNPRINTF)
- MESSAGE(FATAL_ERROR "No vsnprintf function found, please report!")
- ENDIF()
-
- ADD_DEFINITIONS(-Dvsnprintf=_vsnprintf)
-ENDIF()
-
CHECK_SYMBOL_EXISTS(isfinite math.h HAVE_ISFINITE)
IF(NOT HAVE_ISFINITE)
CHECK_FUNCTION_EXISTS(finite HAVE_FINITE)
@@ -367,6 +413,10 @@ ENDIF()
# Check if we have Windows headers
CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0501)
IF(NOT HAVE_WINDOWS_H)
+ # These are needed on some systems for extra features
+ ADD_DEFINITIONS(-D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700)
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700")
+
CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
IF(NOT HAVE_GETTIMEOFDAY)
MESSAGE(FATAL_ERROR "No timing function found!")
@@ -377,12 +427,6 @@ IF(NOT HAVE_WINDOWS_H)
MESSAGE(FATAL_ERROR "No sleep function found!")
ENDIF()
- CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD)
- IF(HAVE_PTHREAD)
- ADD_DEFINITIONS(-pthread)
- SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread)
- ENDIF()
-
# We need pthreads outside of Windows
CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
IF(NOT HAVE_PTHREAD_H)
@@ -391,14 +435,24 @@ IF(NOT HAVE_WINDOWS_H)
# Some systems need pthread_np.h to get recursive mutexes
CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H)
- # _GNU_SOURCE is needed on some systems for extra attributes
- ADD_DEFINITIONS(-D_GNU_SOURCE=1)
+ CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD)
+ IF(HAVE_PTHREAD)
+ ADD_DEFINITIONS(-pthread)
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -pthread")
+ SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread)
+ ENDIF()
+
CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD)
IF(HAVE_LIBPTHREAD)
SET(EXTRA_LIBS pthread ${EXTRA_LIBS})
ENDIF()
- CHECK_LIBRARY_EXISTS(pthread pthread_setschedparam "" HAVE_PTHREAD_SETSCHEDPARAM)
+ CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM)
+
+ CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
+ IF(NOT HAVE_PTHREAD_SETNAME_NP)
+ CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
+ ENDIF()
CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT)
IF(HAVE_LIBRT)
@@ -410,8 +464,8 @@ ENDIF()
CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
IF(NOT HAVE_STDINT_H)
IF(HAVE_WINDOWS_H)
- CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0501
- \#include <windows.h>
+ CHECK_C_SOURCE_COMPILES("#define _WIN32_WINNT 0x0501
+ #include <windows.h>
__int64 foo;
int main() {return 0;}" HAVE___INT64)
ENDIF()
@@ -438,7 +492,11 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
OpenAL32/alError.c
OpenAL32/alExtension.c
OpenAL32/alFilter.c
+ OpenAL32/alFontsound.c
OpenAL32/alListener.c
+ OpenAL32/alMidi.c
+ OpenAL32/alPreset.c
+ OpenAL32/alSoundfont.c
OpenAL32/alSource.c
OpenAL32/alState.c
OpenAL32/alThunk.c
@@ -446,16 +504,23 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
SET(ALC_OBJS Alc/ALc.c
Alc/ALu.c
Alc/alcConfig.c
- Alc/alcDedicated.c
- Alc/alcEcho.c
- Alc/alcModulator.c
- Alc/alcReverb.c
Alc/alcRing.c
- Alc/alcThread.c
Alc/bs2b.c
+ Alc/effects/autowah.c
+ Alc/effects/chorus.c
+ Alc/effects/compressor.c
+ Alc/effects/dedicated.c
+ Alc/effects/distortion.c
+ Alc/effects/echo.c
+ Alc/effects/equalizer.c
+ Alc/effects/flanger.c
+ Alc/effects/modulator.c
+ Alc/effects/null.c
+ Alc/effects/reverb.c
Alc/helpers.c
- Alc/panning.c
Alc/hrtf.c
+ Alc/panning.c
+ Alc/threads.c
Alc/mixer.c
Alc/mixer_c.c
)
@@ -497,6 +562,32 @@ ENDIF()
SET(ALC_OBJS ${ALC_OBJS}
+ Alc/midi/base.c
+ Alc/midi/sf2load.c
+ Alc/midi/dummy.c
+ Alc/midi/fluidsynth.c
+)
+
+SET(HAVE_FLUIDSYNTH 0)
+
+# Check for FluidSynth support
+IF(ALSOFT_MIDI_FLUIDSYNTH)
+ FIND_PACKAGE(FluidSynth)
+ IF(FLUIDSYNTH_FOUND)
+ SET(HAVE_FLUIDSYNTH 1)
+ IF(CMAKE_VERSION VERSION_LESS "2.8.8")
+ INCLUDE_DIRECTORIES(${FLUIDSYNTH_INCLUDE_DIR})
+ ENDIF()
+ SET(EXTRA_LIBS ${FLUIDSYNTH_LIBRARIES} ${EXTRA_LIBS})
+ ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_FLUIDSYNTH AND NOT HAVE_FLUIDSYNTH)
+ MESSAGE(FATAL_ERROR "Failed to enabled required FluidSynth support")
+ENDIF()
+
+
+SET(ALC_OBJS ${ALC_OBJS}
+ Alc/backends/base.c
# Default backends, always available
Alc/backends/loopback.c
Alc/backends/null.c
@@ -507,6 +598,7 @@ SET(HAVE_ALSA 0)
SET(HAVE_OSS 0)
SET(HAVE_SOLARIS 0)
SET(HAVE_SNDIO 0)
+SET(HAVE_QSA 0)
SET(HAVE_DSOUND 0)
SET(HAVE_MMDEVAPI 0)
SET(HAVE_WINMM 0)
@@ -580,6 +672,23 @@ IF(ALSOFT_REQUIRE_SNDIO AND NOT HAVE_SNDIO)
MESSAGE(FATAL_ERROR "Failed to enabled required SndIO backend")
ENDIF()
+# Check QSA backend
+IF (ALSOFT_BACKEND_QSA AND "${CMAKE_C_PLATFORM_ID}" STREQUAL "QNX")
+ CHECK_INCLUDE_FILE(sys/asoundlib.h HAVE_SYS_ASOUNDLIB_H)
+ IF(HAVE_SYS_ASOUNDLIB_H)
+ CHECK_SHARED_FUNCTION_EXISTS(snd_pcm_open "sys/asoundlib.h" asound "" HAVE_LIBASOUND)
+ IF(HAVE_LIBASOUND)
+ SET(HAVE_QSA 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.c)
+ SET(EXTRA_LIBS asound ${EXTRA_LIBS})
+ SET(BACKENDS "${BACKENDS} QSA \(linked\),")
+ ENDIF()
+ ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_QSA AND NOT HAVE_QSA)
+ MESSAGE(FATAL_ERROR "Failed to enabled required QSA backend")
+ENDIF()
+
# Check for MMDevApi backend
IF(HAVE_WINDOWS_H)
IF(ALSOFT_BACKEND_MMDEVAPI)
@@ -675,7 +784,7 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO)
ENDIF()
# Check CoreAudio backend
-IF(COREAUDIO)
+IF(ALSOFT_BACKEND_COREAUDIO)
CHECK_INCLUDE_FILE(/System/Library/Frameworks/CoreAudio.framework/Headers/CoreAudio.h HAVE_COREAUDIO_FRAMEWORK)
IF(HAVE_COREAUDIO_FRAMEWORK)
SET(HAVE_COREAUDIO 1)
@@ -729,9 +838,17 @@ ENDIF()
# This is always available
SET(BACKENDS "${BACKENDS} Null")
+IF(ALSOFT_UTILS AND NOT ALSOFT_NO_CONFIG_UTIL)
+ add_subdirectory(utils/alsoft-config)
+ENDIF()
IF(ALSOFT_EXAMPLES)
- # Might be able to use earlier versions, but these definitely work
- PKG_CHECK_MODULES(FFMPEG libavcodec>=53.61.100 libavformat>=53.32.100 libavutil>=51.35.100)
+ FIND_PACKAGE(SDL)
+ IF(SDL_FOUND)
+ FIND_PACKAGE(SDL_sound)
+ IF(SDL_SOUND_FOUND AND CMAKE_VERSION VERSION_LESS "2.8.8")
+ INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
+ ENDIF()
+ ENDIF()
ENDIF()
IF(LIBTYPE STREQUAL "STATIC")
@@ -758,9 +875,15 @@ CONFIGURE_FILE(
# Build a library
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
-SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES DEFINE_SYMBOL AL_BUILD_LIBRARY
- COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES
- VERSION ${LIB_VERSION}
+SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES)
+IF(WIN32 AND ALSOFT_NO_UID_DEFS)
+ SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
+ENDIF()
+SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
+IF(FLUIDSYNTH_FOUND)
+ SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${FLUIDSYNTH_INCLUDE_DIR})
+ENDIF()
+SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
@@ -793,6 +916,10 @@ MESSAGE(STATUS "")
MESSAGE(STATUS "Building with support for CPU extensions:")
MESSAGE(STATUS " ${CPU_EXTS}")
MESSAGE(STATUS "")
+IF(HAVE_FLUIDSYNTH)
+ MESSAGE(STATUS "FluidSynth support for ALC_SOFT_midi_interface enabled")
+ MESSAGE(STATUS "")
+ENDIF()
IF(WIN32)
IF(NOT HAVE_DSOUND)
@@ -825,37 +952,44 @@ IF(ALSOFT_UTILS)
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
+
MESSAGE(STATUS "Building utility programs")
+ IF(TARGET alsoft-config)
+ MESSAGE(STATUS "Building configuration program")
+ ENDIF()
MESSAGE(STATUS "")
ENDIF()
IF(ALSOFT_EXAMPLES)
- IF(FFMPEG_FOUND)
- ADD_EXECUTABLE(alstream examples/common/alhelpers.c
- examples/common/alffmpeg.c
- examples/alstream.c)
- TARGET_LINK_LIBRARIES(alstream ${FFMPEG_LIBRARIES} ${LIBNAME})
- SET_TARGET_PROPERTIES(alstream PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}")
-
- ADD_EXECUTABLE(alreverb examples/common/alhelpers.c
- examples/common/alffmpeg.c
- examples/alreverb.c)
- TARGET_LINK_LIBRARIES(alreverb ${FFMPEG_LIBRARIES} ${LIBNAME})
- SET_TARGET_PROPERTIES(alreverb PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}")
-
- ADD_EXECUTABLE(allatency examples/common/alhelpers.c
- examples/common/alffmpeg.c
- examples/allatency.c)
- TARGET_LINK_LIBRARIES(allatency ${FFMPEG_LIBRARIES} ${LIBNAME})
- SET_TARGET_PROPERTIES(allatency PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}")
-
- INSTALL(TARGETS alstream alreverb allatency
+ IF(SDL_FOUND AND SDL_SOUND_FOUND)
+ ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c
+ examples/common/sdl_sound.c)
+ SET_PROPERTY(TARGET ex-common APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL_SOUND_INCLUDE_DIR})
+
+ ADD_EXECUTABLE(alstream examples/alstream.c)
+ TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${LIBNAME})
+ SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL_SOUND_INCLUDE_DIR})
+
+ ADD_EXECUTABLE(alreverb examples/alreverb.c)
+ TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${LIBNAME})
+ SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL_SOUND_INCLUDE_DIR})
+
+ ADD_EXECUTABLE(allatency examples/allatency.c)
+ TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${LIBNAME})
+ SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL_SOUND_INCLUDE_DIR})
+
+ ADD_EXECUTABLE(alloopback examples/alloopback.c)
+ TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL_LIBRARY} ${LIBNAME})
+ SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL_INCLUDE_DIR}
+ ${SDL_SOUND_INCLUDE_DIR})
+
+ INSTALL(TARGETS alstream alreverb allatency alloopback
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
- MESSAGE(STATUS "Building ffmpeg example programs")
+ MESSAGE(STATUS "Building example programs")
MESSAGE(STATUS "")
ENDIF()
ENDIF()
diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h
index 4c14b1f7..c7182d9b 100644
--- a/OpenAL32/Include/alAuxEffectSlot.h
+++ b/OpenAL32/Include/alAuxEffectSlot.h
@@ -8,17 +8,62 @@
extern "C" {
#endif
+struct ALeffectStateVtable;
+struct ALeffectslot;
+
typedef struct ALeffectState {
- ALvoid (*Destroy)(struct ALeffectState *State);
- ALboolean (*DeviceUpdate)(struct ALeffectState *State, ALCdevice *Device);
- ALvoid (*Update)(struct ALeffectState *State, ALCdevice *Device, const struct ALeffectslot *Slot);
- ALvoid (*Process)(struct ALeffectState *State, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]);
+ const struct ALeffectStateVtable *vtbl;
} ALeffectState;
+struct ALeffectStateVtable {
+ void (*const Destruct)(ALeffectState *state);
+
+ ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
+ void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
+ void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]);
+
+ void (*const Delete)(struct ALeffectState *state);
+};
+
+#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
+DECLARE_THUNK(T, ALeffectState, void, Destruct) \
+DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
+DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
+DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \
+DECLARE_THUNK(T, ALeffectState, void, Delete) \
+ \
+static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
+ T##_ALeffectState_Destruct, \
+ \
+ T##_ALeffectState_deviceUpdate, \
+ T##_ALeffectState_update, \
+ T##_ALeffectState_process, \
+ \
+ T##_ALeffectState_Delete, \
+}
+
+
+struct ALeffectStateFactoryVtable;
+
+typedef struct ALeffectStateFactory {
+ const struct ALeffectStateFactoryVtable *vtbl;
+} ALeffectStateFactory;
+
+struct ALeffectStateFactoryVtable {
+ ALeffectState *(*const create)(ALeffectStateFactory *factory);
+};
-typedef struct ALeffectslot
-{
- ALeffect effect;
+#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
+DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
+ \
+static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
+ T##_ALeffectStateFactory_create, \
+}
+
+
+typedef struct ALeffectslot {
+ ALenum EffectType;
+ ALeffectProps EffectProps;
volatile ALfloat Gain;
volatile ALboolean AuxSendAuto;
@@ -37,23 +82,34 @@ typedef struct ALeffectslot
ALuint id;
} ALeffectslot;
+inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
+{ return (struct ALeffectslot*)LookupUIntMapKey(&context->EffectSlotMap, id); }
+inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
+{ return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); }
ALenum InitEffectSlot(ALeffectslot *slot);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
-ALeffectState *NoneCreate(void);
-ALeffectState *ReverbCreate(void);
-ALeffectState *EchoCreate(void);
-ALeffectState *ModulatorCreate(void);
-ALeffectState *DedicatedCreate(void);
-#define ALeffectState_Destroy(a) ((a)->Destroy((a)))
-#define ALeffectState_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b)))
-#define ALeffectState_Update(a,b,c) ((a)->Update((a),(b),(c)))
-#define ALeffectState_Process(a,b,c,d) ((a)->Process((a),(b),(c),(d)))
+ALeffectStateFactory *ALnullStateFactory_getFactory(void);
+ALeffectStateFactory *ALreverbStateFactory_getFactory(void);
+ALeffectStateFactory *ALautowahStateFactory_getFactory(void);
+ALeffectStateFactory *ALchorusStateFactory_getFactory(void);
+ALeffectStateFactory *ALcompressorStateFactory_getFactory(void);
+ALeffectStateFactory *ALdistortionStateFactory_getFactory(void);
+ALeffectStateFactory *ALechoStateFactory_getFactory(void);
+ALeffectStateFactory *ALequalizerStateFactory_getFactory(void);
+ALeffectStateFactory *ALflangerStateFactory_getFactory(void);
+ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void);
+
+ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
+
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
+void InitEffectFactoryMap(void);
+void DeinitEffectFactoryMap(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h
index 8ecc4dd8..d22b3b9b 100644
--- a/OpenAL32/Include/alBuffer.h
+++ b/OpenAL32/Include/alBuffer.h
@@ -35,8 +35,7 @@ enum UserFmtChannels {
ALuint BytesFromUserFmt(enum UserFmtType type);
ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
-static __inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans,
- enum UserFmtType type)
+inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
{
return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
}
@@ -57,17 +56,17 @@ enum FmtChannels {
FmtX61 = UserFmtX61,
FmtX71 = UserFmtX71,
};
+#define MAX_INPUT_CHANNELS (8)
ALuint BytesFromFmt(enum FmtType type);
ALuint ChannelsFromFmt(enum FmtChannels chans);
-static __inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
+inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
{
return ChannelsFromFmt(chans) * BytesFromFmt(type);
}
-typedef struct ALbuffer
-{
+typedef struct ALbuffer {
ALvoid *data;
ALsizei Frequency;
@@ -93,6 +92,11 @@ typedef struct ALbuffer
ALuint id;
} ALbuffer;
+inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
+{ return (struct ALbuffer*)LookupUIntMapKey(&device->BufferMap, id); }
+inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
+{ return (struct ALbuffer*)RemoveUIntMapKey(&device->BufferMap, id); }
+
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus
diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h
index ba894c8b..f656c56a 100644
--- a/OpenAL32/Include/alEffect.h
+++ b/OpenAL32/Include/alEffect.h
@@ -7,10 +7,18 @@
extern "C" {
#endif
+struct ALeffect;
+
enum {
EAXREVERB = 0,
REVERB,
+ AUTOWAH,
+ CHORUS,
+ COMPRESSOR,
+ DISTORTION,
ECHO,
+ EQUALIZER,
+ FLANGER,
MODULATOR,
DEDICATED,
@@ -21,11 +29,41 @@ extern ALboolean DisabledEffects[MAX_EFFECTS];
extern ALfloat ReverbBoost;
extern ALboolean EmulateEAXReverb;
-typedef struct ALeffect
-{
- // Effect type (AL_EFFECT_NULL, ...)
- ALenum type;
+struct ALeffectVtable {
+ void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
+ void (*const setParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals);
+ void (*const setParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val);
+ void (*const setParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals);
+
+ void (*const getParami)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *val);
+ void (*const getParamiv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals);
+ void (*const getParamf)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val);
+ void (*const getParamfv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals);
+};
+
+#define DEFINE_ALEFFECT_VTABLE(T) \
+const struct ALeffectVtable T##_vtable = { \
+ T##_setParami, T##_setParamiv, \
+ T##_setParamf, T##_setParamfv, \
+ T##_getParami, T##_getParamiv, \
+ T##_getParamf, T##_getParamfv, \
+}
+extern const struct ALeffectVtable ALeaxreverb_vtable;
+extern const struct ALeffectVtable ALreverb_vtable;
+extern const struct ALeffectVtable ALautowah_vtable;
+extern const struct ALeffectVtable ALchorus_vtable;
+extern const struct ALeffectVtable ALcompressor_vtable;
+extern const struct ALeffectVtable ALdistortion_vtable;
+extern const struct ALeffectVtable ALecho_vtable;
+extern const struct ALeffectVtable ALequalizer_vtable;
+extern const struct ALeffectVtable ALflanger_vtable;
+extern const struct ALeffectVtable ALmodulator_vtable;
+extern const struct ALeffectVtable ALnull_vtable;
+extern const struct ALeffectVtable ALdedicated_vtable;
+
+
+typedef union ALeffectProps {
struct {
// Shared Reverb Properties
ALfloat Density;
@@ -56,6 +94,34 @@ typedef struct ALeffect
} Reverb;
struct {
+ ALfloat AttackTime;
+ ALfloat ReleaseTime;
+ ALfloat PeakGain;
+ ALfloat Resonance;
+ } Autowah;
+
+ struct {
+ ALint Waveform;
+ ALint Phase;
+ ALfloat Rate;
+ ALfloat Depth;
+ ALfloat Feedback;
+ ALfloat Delay;
+ } Chorus;
+
+ struct {
+ ALboolean OnOff;
+ } Compressor;
+
+ struct {
+ ALfloat Edge;
+ ALfloat Gain;
+ ALfloat LowpassCutoff;
+ ALfloat EQCenter;
+ ALfloat EQBandwidth;
+ } Distortion;
+
+ struct {
ALfloat Delay;
ALfloat LRDelay;
@@ -66,6 +132,29 @@ typedef struct ALeffect
} Echo;
struct {
+ ALfloat Delay;
+ ALfloat LowCutoff;
+ ALfloat LowGain;
+ ALfloat Mid1Center;
+ ALfloat Mid1Gain;
+ ALfloat Mid1Width;
+ ALfloat Mid2Center;
+ ALfloat Mid2Gain;
+ ALfloat Mid2Width;
+ ALfloat HighCutoff;
+ ALfloat HighGain;
+ } Equalizer;
+
+ struct {
+ ALint Waveform;
+ ALint Phase;
+ ALfloat Rate;
+ ALfloat Depth;
+ ALfloat Feedback;
+ ALfloat Delay;
+ } Flanger;
+
+ struct {
ALfloat Frequency;
ALfloat HighPassCutoff;
ALint Waveform;
@@ -74,32 +163,26 @@ typedef struct ALeffect
struct {
ALfloat Gain;
} Dedicated;
+} ALeffectProps;
- void (*SetParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
- void (*SetParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals);
- void (*SetParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val);
- void (*SetParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals);
+typedef struct ALeffect {
+ // Effect type (AL_EFFECT_NULL, ...)
+ ALenum type;
+
+ ALeffectProps Props;
- void (*GetParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *val);
- void (*GetParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals);
- void (*GetParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val);
- void (*GetParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals);
+ const struct ALeffectVtable *vtbl;
/* Self ID */
ALuint id;
} ALeffect;
-#define ALeffect_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v)))
-#define ALeffect_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v)))
-#define ALeffect_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v)))
-#define ALeffect_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v)))
-
-#define ALeffect_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v)))
-#define ALeffect_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v)))
-#define ALeffect_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v)))
-#define ALeffect_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
+inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
+{ return (struct ALeffect*)LookupUIntMapKey(&device->EffectMap, id); }
+inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
+{ return (struct ALeffect*)RemoveUIntMapKey(&device->EffectMap, id); }
-static __inline ALboolean IsReverbEffect(ALenum type)
+inline ALboolean IsReverbEffect(ALenum type)
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
ALenum InitEffect(ALeffect *effect);
diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h
index 0ade342d..ab91d27b 100644
--- a/OpenAL32/Include/alError.h
+++ b/OpenAL32/Include/alError.h
@@ -11,6 +11,21 @@ extern ALboolean TrapALError;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
+#define SET_ERROR_AND_RETURN(ctx, err) do { \
+ alSetError((ctx), (err)); \
+ return; \
+} while(0)
+
+#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \
+ alSetError((ctx), (err)); \
+ return (val); \
+} while(0)
+
+#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
+ alSetError((ctx), (err)); \
+ goto lbl; \
+} while(0)
+
#ifdef __cplusplus
}
#endif
diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h
index 09cef93c..5167c125 100644
--- a/OpenAL32/Include/alFilter.h
+++ b/OpenAL32/Include/alFilter.h
@@ -9,45 +9,56 @@ extern "C" {
#define LOWPASSFREQREF (5000)
-typedef struct {
- ALfloat coeff;
-#ifndef _MSC_VER
- ALfloat history[0];
-#else
- ALfloat history[1];
-#endif
-} FILTER;
-static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input)
-{
- ALfloat *history = &iir->history[offset*2];
- ALfloat a = iir->coeff;
- ALfloat output = input;
+/* Filters implementation is based on the "Cookbook formulae for audio *
+ * EQ biquad filter coefficients" by Robert Bristow-Johnson *
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
- output = output + (history[0]-output)*a;
- history[0] = output;
- output = output + (history[1]-output)*a;
- history[1] = output;
+typedef enum ALfilterType {
+ ALfilterType_HighShelf,
+ ALfilterType_LowShelf,
+ ALfilterType_Peaking,
- return output;
-}
+ ALfilterType_LowPass,
+ ALfilterType_HighPass,
+ ALfilterType_BandPass,
+} ALfilterType;
-static __inline ALfloat lpFilter2PC(const FILTER *iir, ALuint offset, ALfloat input)
-{
- const ALfloat *history = &iir->history[offset*2];
- ALfloat a = iir->coeff;
- ALfloat output = input;
+typedef struct ALfilterState {
+ ALfloat x[2]; /* History of two last input samples */
+ ALfloat y[2]; /* History of two last output samples */
+ ALfloat a[3]; /* Transfer function coefficients "a" */
+ ALfloat b[3]; /* Transfer function coefficients "b" */
+} ALfilterState;
- output = output + (history[0]-output)*a;
- output = output + (history[1]-output)*a;
+void ALfilterState_clear(ALfilterState *filter);
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_scale, ALfloat bandwidth);
- return output;
+inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
+{
+ ALfloat outsmp;
+
+ outsmp = filter->b[0] * sample +
+ filter->b[1] * filter->x[0] +
+ filter->b[2] * filter->x[1] -
+ filter->a[1] * filter->y[0] -
+ filter->a[2] * filter->y[1];
+ filter->x[1] = filter->x[0];
+ filter->x[0] = sample;
+ filter->y[1] = filter->y[0];
+ filter->y[0] = outsmp;
+
+ return outsmp;
}
-/* Calculates the low-pass filter coefficient given the pre-scaled gain and
- * cos(w) value. Note that g should be pre-scaled (sqr(gain) for one-pole,
- * sqrt(gain) for four-pole, etc) */
-ALfloat lpCoeffCalc(ALfloat g, ALfloat cw);
+inline ALfloat ALfilterState_processSingleC(const ALfilterState *filter, ALfloat sample)
+{
+ return filter->b[0] * sample +
+ filter->b[1] * filter->x[0] +
+ filter->b[2] * filter->x[1] -
+ filter->a[1] * filter->y[0] -
+ filter->a[2] * filter->y[1];
+}
typedef struct ALfilter {
@@ -81,6 +92,11 @@ typedef struct ALfilter {
#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v)))
#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
+inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
+{ return (struct ALfilter*)LookupUIntMapKey(&device->FilterMap, id); }
+inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
+{ return (struct ALfilter*)RemoveUIntMapKey(&device->FilterMap, id); }
+
ALvoid ReleaseALFilters(ALCdevice *device);
#ifdef __cplusplus
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 1110e89e..b6a9f0ae 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -7,6 +7,10 @@
#include <assert.h>
#include <math.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
@@ -15,37 +19,259 @@
#include "AL/alc.h"
#include "AL/alext.h"
-#ifndef AL_SOFT_deferred_updates
-#define AL_SOFT_deferred_updates 1
-#define AL_DEFERRED_UPDATES_SOFT 0xC002
-typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void);
-typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void);
+#include "atomic.h"
+#include "uintmap.h"
+
+#ifndef ALC_SOFT_HRTF
+#define ALC_SOFT_HRTF 1
+#define ALC_HRTF_SOFT 0x1992
+#endif
+
+#ifndef ALC_SOFT_midi_interface
+#define ALC_SOFT_midi_interface 1
+#define AL_MIDI_CLOCK_SOFT 0x9999
+#define AL_MIDI_STATE_SOFT 0x9986
+#define AL_MIDI_GAIN_SOFT 0x9998
+#define AL_MIDI_PRESET_SOFT 0x9997
+#define AL_MIDI_BANK_SOFT 0x9996
+#define AL_SOUNDFONTS_SIZE_SOFT 0x9995
+#define AL_SOUNDFONTS_SOFT 0x9994
+#define AL_PRESETS_SIZE_SOFT 0x9993
+#define AL_PRESETS_SOFT 0x9992
+#define AL_FONTSOUNDS_SIZE_SOFT 0x9991
+#define AL_FONTSOUNDS_SOFT 0x9990
+
+#define AL_SOURCE0_INPUT_SOFT 0x998F
+#define AL_SOURCE0_TYPE_SOFT 0x998E
+#define AL_SOURCE0_FORM_SOFT 0x998D
+#define AL_SOURCE1_INPUT_SOFT 0x998C
+#define AL_SOURCE1_TYPE_SOFT 0x998B
+#define AL_SOURCE1_FORM_SOFT 0x998A
+#define AL_AMOUNT_SOFT 0x9989
+#define AL_TRANSFORM_OP_SOFT 0x9988
+#define AL_DESTINATION_SOFT 0x9987
+
+/* Sounce Input */
+#define AL_ONE_SOFT 0x0080
+#define AL_NOTEON_VELOCITY_SOFT 0x0082
+#define AL_NOTEON_KEY_SOFT 0x0083
+/* AL_KEYPRESSURE_SOFT */
+/* AL_CHANNELPRESSURE_SOFT */
+/* AL_PITCHBEND_SOFT */
+#define AL_PITCHBEND_SENSITIVITY_SOFT 0x0090
+/* CC 0...127 */
+
+/* Source Type */
+#define AL_UNORM_SOFT 0x0000
+#define AL_UNORM_REV_SOFT 0x0100
+#define AL_SNORM_SOFT 0x0200
+#define AL_SNORM_REV_SOFT 0x0300
+
+/* Source Form */
+#define AL_LINEAR_SOFT 0x0000
+#define AL_CONCAVE_SOFT 0x0400
+#define AL_CONVEX_SOFT 0x0800
+#define AL_SWITCH_SOFT 0x0C00
+
+/* Transform op */
+/* AL_LINEAR_SOFT */
+#define AL_ABSOLUTE_SOFT 0x0002
+
+#define AL_SAMPLE_START_SOFT 0x2000
+#define AL_SAMPLE_END_SOFT 0x2001
+#define AL_SAMPLE_LOOP_START_SOFT 0x2002
+#define AL_SAMPLE_LOOP_END_SOFT 0x2003
+#define AL_SAMPLE_RATE_SOFT 0x2004
+#define AL_BASE_KEY_SOFT 0x2005
+#define AL_KEY_CORRECTION_SOFT 0x2006
+#define AL_SAMPLE_TYPE_SOFT 0x2007
+#define AL_FONTSOUND_LINK_SOFT 0x2008
+#define AL_MOD_LFO_TO_PITCH_SOFT 0x0005
+#define AL_VIBRATO_LFO_TO_PITCH_SOFT 0x0006
+#define AL_MOD_ENV_TO_PITCH_SOFT 0x0007
+#define AL_FILTER_CUTOFF_SOFT 0x0008
+#define AL_FILTER_RESONANCE_SOFT 0x0009
+#define AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT 0x000A
+#define AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT 0x000B
+#define AL_MOD_LFO_TO_VOLUME_SOFT 0x000D
+#define AL_CHORUS_SEND_SOFT 0x000F
+#define AL_REVERB_SEND_SOFT 0x0010
+#define AL_PAN_SOFT 0x0011
+#define AL_MOD_LFO_DELAY_SOFT 0x0015
+#define AL_MOD_LFO_FREQUENCY_SOFT 0x0016
+#define AL_VIBRATO_LFO_DELAY_SOFT 0x0017
+#define AL_VIBRATO_LFO_FREQUENCY_SOFT 0x0018
+#define AL_MOD_ENV_DELAYTIME_SOFT 0x0019
+#define AL_MOD_ENV_ATTACKTIME_SOFT 0x001A
+#define AL_MOD_ENV_HOLDTIME_SOFT 0x001B
+#define AL_MOD_ENV_DECAYTIME_SOFT 0x001C
+#define AL_MOD_ENV_SUSTAINVOLUME_SOFT 0x001D
+#define AL_MOD_ENV_RELEASETIME_SOFT 0x002E
+#define AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT 0x001F
+#define AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT 0x0020
+#define AL_VOLUME_ENV_DELAYTIME_SOFT 0x0021
+#define AL_VOLUME_ENV_ATTACKTIME_SOFT 0x0022
+#define AL_VOLUME_ENV_HOLDTIME_SOFT 0x0023
+#define AL_VOLUME_ENV_DECAYTIME_SOFT 0x0024
+#define AL_VOLUME_ENV_SUSTAINVOLUME_SOFT 0x0025
+#define AL_VOLUME_ENV_RELEASETIME_SOFT 0x0026
+#define AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT 0x0027
+#define AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT 0x0028
+#define AL_KEY_RANGE_SOFT 0x002B
+#define AL_VELOCITY_RANGE_SOFT 0x002C
+#define AL_ATTENUATION_SOFT 0x0030
+#define AL_TUNING_COARSE_SOFT 0x0033
+#define AL_TUNING_FINE_SOFT 0x0034
+#define AL_LOOP_MODE_SOFT 0x0036
+#define AL_TUNING_SCALE_SOFT 0x0038
+#define AL_EXCLUSIVE_CLASS_SOFT 0x0039
+#define AL_LOOP_CONTINUOUS_SOFT 0x0001
+#define AL_LOOP_UNTIL_RELEASE_SOFT 0x0003
+#define AL_RIGHT_SOFT 0x0002
+#define AL_LEFT_SOFT 0x0004
+#define AL_FORMAT_TYPE_SOFT 0x1991
+#define AL_NOTEOFF_SOFT 0x0080
+#define AL_NOTEON_SOFT 0x0090
+#define AL_KEYPRESSURE_SOFT 0x00A0
+#define AL_CONTROLLERCHANGE_SOFT 0x00B0
+#define AL_PROGRAMCHANGE_SOFT 0x00C0
+#define AL_CHANNELPRESSURE_SOFT 0x00D0
+#define AL_PITCHBEND_SOFT 0x00E0
+typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids);
+typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids);
+typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id);
+typedef void (AL_APIENTRY*LPALSOUNDFONTSAMPLESSOFT)(ALuint sfid, ALenum type, ALsizei count, const ALvoid *samples);
+typedef void (AL_APIENTRY*LPALGETSOUNDFONTSAMPLESSOFT)(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples);
+typedef ALvoid* (AL_APIENTRY*LPALSOUNDFONTMAPSAMPLESSOFT)(ALuint sfid, ALsizei offset, ALsizei length);
+typedef void (AL_APIENTRY*LPALSOUNDFONTUNMAPSAMPLESSOFT)(ALuint sfid);
+typedef void (AL_APIENTRY*LPALGETSOUNDFONTIVSOFT)(ALuint id, ALenum param, ALint *values);
+typedef void (AL_APIENTRY*LPALSOUNDFONTPRESETSSOFT)(ALuint id, ALsizei count, const ALuint *pids);
+typedef void (AL_APIENTRY*LPALGENPRESETSSOFT)(ALsizei n, ALuint *ids);
+typedef void (AL_APIENTRY*LPALDELETEPRESETSSOFT)(ALsizei n, const ALuint *ids);
+typedef ALboolean (AL_APIENTRY*LPALISPRESETSOFT)(ALuint id);
+typedef void (AL_APIENTRY*LPALPRESETISOFT)(ALuint id, ALenum param, ALint value);
+typedef void (AL_APIENTRY*LPALPRESETIVSOFT)(ALuint id, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY*LPALPRESETFONTSOUNDSSOFT)(ALuint id, ALsizei count, const ALuint *fsids);
+typedef void (AL_APIENTRY*LPALGETPRESETIVSOFT)(ALuint id, ALenum param, ALint *values);
+typedef void (AL_APIENTRY*LPALGENFONTSOUNDSSOFT)(ALsizei n, ALuint *ids);
+typedef void (AL_APIENTRY*LPALDELETEFONTSOUNDSSOFT)(ALsizei n, const ALuint *ids);
+typedef ALboolean (AL_APIENTRY*LPALISFONTSOUNDSOFT)(ALuint id);
+typedef void (AL_APIENTRY*LPALFONTSOUNDISOFT)(ALuint id, ALenum param, ALint value);
+typedef void (AL_APIENTRY*LPALFONTSOUND2ISOFT)(ALuint id, ALenum param, ALint value1, ALint value2);
+typedef void (AL_APIENTRY*LPALFONTSOUNDIVSOFT)(ALuint id, ALenum param, const ALint *values);
+typedef void (AL_APIENTRY*LPALGETFONTSOUNDIVSOFT)(ALuint id, ALenum param, ALint *values);
+typedef void (AL_APIENTRY*LPALFONTSOUNDMOFULATORISOFT)(ALuint id, ALsizei stage, ALenum param, ALint value);
+typedef void (AL_APIENTRY*LPALGETFONTSOUNDMODULATORIVSOFT)(ALuint id, ALsizei stage, ALenum param, ALint *values);
+typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(ALuint id);
+typedef void (AL_APIENTRY*LPALMIDISOUNDFONTVSOFT)(ALsizei count, const ALuint *ids);
+typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
+typedef void (AL_APIENTRY*LPALMIDISYSEXSOFT)(ALuint64SOFT time, const ALbyte *data, ALsizei size);
+typedef void (AL_APIENTRY*LPALMIDIPLAYSOFT)(void);
+typedef void (AL_APIENTRY*LPALMIDIPAUSESOFT)(void);
+typedef void (AL_APIENTRY*LPALMIDISTOPSOFT)(void);
+typedef void (AL_APIENTRY*LPALMIDIRESETSOFT)(void);
+typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value);
+typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname);
+typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values);
+typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
#ifdef AL_ALEXT_PROTOTYPES
-AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void);
-AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
+AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids);
+AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids);
+AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id);
+AL_API void AL_APIENTRY alSoundfontSamplesSOFT(ALuint sfid, ALenum type, ALsizei count, const ALvoid *samples);
+AL_API void AL_APIENTRY alGetSoundfontSamplesSOFT(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples);
+AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint sfid, ALsizei offset, ALsizei length);
+AL_API void AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint sfid);
+AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values);
+AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids);
+
+AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids);
+AL_API void AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids);
+AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id);
+AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value);
+AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values);
+AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values);
+AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids);
+
+AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids);
+AL_API void AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids);
+AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id);
+AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value);
+AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2);
+AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values);
+AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values);
+AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value);
+AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values);
+
+AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id);
+AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids);
+AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
+AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size);
+AL_API void AL_APIENTRY alMidiPlaySOFT(void);
+AL_API void AL_APIENTRY alMidiPauseSOFT(void);
+AL_API void AL_APIENTRY alMidiStopSOFT(void);
+AL_API void AL_APIENTRY alMidiResetSOFT(void);
+AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value);
+AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname);
+AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values);
+AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
#endif
#endif
+#ifndef ALC_SOFT_pause_device
+#define ALC_SOFT_pause_device 1
+typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device);
+typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
+#endif
+#endif
-#if defined(HAVE_STDINT_H)
-#include <stdint.h>
-typedef int64_t ALint64;
-typedef uint64_t ALuint64;
-#elif defined(HAVE___INT64)
-typedef __int64 ALint64;
-typedef unsigned __int64 ALuint64;
-#elif (SIZEOF_LONG == 8)
-typedef long ALint64;
-typedef unsigned long ALuint64;
-#elif (SIZEOF_LONG_LONG == 8)
-typedef long long ALint64;
-typedef unsigned long long ALuint64;
+
+#ifdef IN_IDE_PARSER
+/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
+ * recent versions (at least 4.5.1) do recognize GCC's __restrict. */
+#define restrict __restrict
+/* KDevelop won't see the ALIGN macro from config.h when viewing files that
+ * don't include it directly (e.g. headers). */
+#ifndef ALIGN
+#define ALIGN(x)
+#endif
#endif
+
+typedef ALint64SOFT ALint64;
+typedef ALuint64SOFT ALuint64;
+
typedef ptrdiff_t ALintptrEXT;
typedef ptrdiff_t ALsizeiptrEXT;
-#define MAKEU64(x,y) (((ALuint64)(x)<<32)|(ALuint64)(y))
+#ifndef U64
+#if defined(_MSC_VER)
+#define U64(x) ((ALuint64)(x##ui64))
+#elif SIZEOF_LONG == 8
+#define U64(x) ((ALuint64)(x##ul))
+#elif SIZEOF_LONG_LONG == 8
+#define U64(x) ((ALuint64)(x##ull))
+#endif
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX U64(18446744073709551615)
+#endif
+
+#ifndef UNUSED
+#if defined(__cplusplus)
+#define UNUSED(x)
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_##x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+#endif
#ifdef HAVE_GCC_FORMAT
#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y))))
@@ -53,6 +279,16 @@ typedef ptrdiff_t ALsizeiptrEXT;
#define PRINTF_STYLE(x, y)
#endif
+#if defined(__GNUC__) && defined(__i386__)
+/* force_align_arg_pointer is required for proper function arguments aligning
+ * when SSE code is used. Some systems (Windows, QNX) do not guarantee our
+ * thread functions will be properly aligned on the stack, even though GCC may
+ * generate code with the assumption that it is. */
+#define FORCE_ALIGN __attribute__((force_align_arg_pointer))
+#else
+#define FORCE_ALIGN
+#endif
+
static const union {
ALuint u;
@@ -62,274 +298,67 @@ static const union {
#define COUNTOF(x) (sizeof((x))/sizeof((x)[0]))
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef DWORD pthread_key_t;
-int pthread_key_create(pthread_key_t *key, void (*callback)(void*));
-int pthread_key_delete(pthread_key_t key);
-void *pthread_getspecific(pthread_key_t key);
-int pthread_setspecific(pthread_key_t key, void *val);
-
-#define HAVE_DYNLOAD 1
-void *LoadLib(const char *name);
-void CloseLib(void *handle);
-void *GetSymbol(void *handle, const char *name);
-
-WCHAR *strdupW(const WCHAR *str);
-
-typedef LONG pthread_once_t;
-#define PTHREAD_ONCE_INIT 0
-void pthread_once(pthread_once_t *once, void (*callback)(void));
-
-static __inline int sched_yield(void)
-{ SwitchToThread(); return 0; }
-
-#else
+#define DERIVE_FROM_TYPE(t) t t##_parent
+#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
+#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
-#include <unistd.h>
-#include <assert.h>
-#include <pthread.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-
-#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0)
-
-typedef pthread_mutex_t CRITICAL_SECTION;
-void InitializeCriticalSection(CRITICAL_SECTION *cs);
-void DeleteCriticalSection(CRITICAL_SECTION *cs);
-void EnterCriticalSection(CRITICAL_SECTION *cs);
-void LeaveCriticalSection(CRITICAL_SECTION *cs);
-
-ALuint timeGetTime(void);
-void Sleep(ALuint t);
-
-#if defined(HAVE_DLFCN_H)
-#define HAVE_DYNLOAD 1
-void *LoadLib(const char *name);
-void CloseLib(void *handle);
-void *GetSymbol(void *handle, const char *name);
-#endif
-#endif
+#define DECLARE_FORWARD(T1, T2, rettype, func) \
+rettype T1##_##func(T1 *obj) \
+{ return T2##_##func(STATIC_CAST(T2, obj)); }
-typedef void *volatile XchgPtr;
+#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
+rettype T1##_##func(T1 *obj, argtype1 a) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a); }
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
-typedef ALuint RefCount;
-static __inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return __sync_add_and_fetch(ptr, 1); }
-static __inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return __sync_sub_and_fetch(ptr, 1); }
+#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b); }
-static __inline int ExchangeInt(volatile int *ptr, int newval)
-{
- return __sync_lock_test_and_set(ptr, newval);
-}
-static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- return __sync_lock_test_and_set(ptr, newval);
-}
-static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- return __sync_bool_compare_and_swap(ptr, oldval, newval);
-}
-static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return __sync_bool_compare_and_swap(ptr, oldval, newval);
-}
+#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-static __inline int xaddl(volatile int *dest, int incr)
-{
- int ret;
- __asm__ __volatile__("lock; xaddl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (incr)
- : "memory");
- return ret;
-}
+#define GET_VTABLE1(T1) (&(T1##_vtable))
+#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
-typedef int RefCount;
-static __inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return xaddl(ptr, 1)+1; }
-static __inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return xaddl(ptr, -1)-1; }
+#define SET_VTABLE1(T1, obj) ((obj)->vtbl = GET_VTABLE1(T1))
+#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
-static __inline int ExchangeInt(volatile int *dest, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; xchgl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory");
- return ret;
-}
+#define DECLARE_THUNK(T1, T2, rettype, func) \
+static rettype T1##_##T2##_##func(T2 *obj) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
-static __inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory");
- return ret == oldval;
-}
+#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
-static __inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; xchgl %0,(%1)"
-#else
- "lock; xchgq %0,(%1)"
-#endif
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory"
- );
- return ret;
-}
+#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
-static __inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; cmpxchgl %2,(%1)"
-#else
- "lock; cmpxchgq %2,(%1)"
-#endif
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory"
- );
- return ret == oldval;
-}
+#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
-#elif defined(_WIN32)
-typedef LONG RefCount;
-static __inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return InterlockedIncrement(ptr); }
-static __inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return InterlockedDecrement(ptr); }
+/* Helper to extract an argument list for VCALL. Not used directly. */
+#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
-extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1];
+/* Call a "virtual" method on an object, with arguments. */
+#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
+/* Call a "virtual" method on an object, with no arguments. */
+#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
-static __inline int ExchangeInt(volatile int *ptr, int newval)
-{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedExchange(u.l, newval);
-}
-static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- return InterlockedExchangePointer(ptr, newval);
-}
-static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedCompareExchange(u.l, newval, oldval) == oldval;
-}
-static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval;
-}
-
-#elif defined(__APPLE__)
-
-#include <libkern/OSAtomic.h>
-
-typedef int32_t RefCount;
-static __inline RefCount IncrementRef(volatile RefCount *ptr)
-{ return OSAtomicIncrement32Barrier(ptr); }
-static __inline RefCount DecrementRef(volatile RefCount *ptr)
-{ return OSAtomicDecrement32Barrier(ptr); }
-
-static __inline int ExchangeInt(volatile int *ptr, int newval)
-{
- /* Really? No regular old atomic swap? */
- int oldval;
- do {
- oldval = *ptr;
- } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr));
- return oldval;
-}
-static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{
- void *oldval;
- do {
- oldval = *ptr;
- } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr));
- return oldval;
-}
-static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{
- return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr);
-}
-static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{
- return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr);
-}
-
-#else
-#error "No atomic functions available on this platform!"
-typedef ALuint RefCount;
-#endif
-
-
-typedef struct {
- volatile RefCount read_count;
- volatile RefCount write_count;
- volatile ALenum read_lock;
- volatile ALenum read_entry_lock;
- volatile ALenum write_lock;
-} RWLock;
-
-void RWLockInit(RWLock *lock);
-void ReadLock(RWLock *lock);
-void ReadUnlock(RWLock *lock);
-void WriteLock(RWLock *lock);
-void WriteUnlock(RWLock *lock);
-
-
-typedef struct UIntMap {
- struct {
- ALuint key;
- ALvoid *value;
- } *array;
- ALsizei size;
- ALsizei maxsize;
- ALsizei limit;
- RWLock lock;
-} UIntMap;
-extern UIntMap TlsDestructor;
-
-void InitUIntMap(UIntMap *map, ALsizei limit);
-void ResetUIntMap(UIntMap *map);
-ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
-ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key);
-ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
-
-static __inline void LockUIntMapRead(UIntMap *map)
-{ ReadLock(&map->lock); }
-static __inline void UnlockUIntMapRead(UIntMap *map)
-{ ReadUnlock(&map->lock); }
-static __inline void LockUIntMapWrite(UIntMap *map)
-{ WriteLock(&map->lock); }
-static __inline void UnlockUIntMapWrite(UIntMap *map)
-{ WriteUnlock(&map->lock); }
+#define DELETE_OBJ(obj) do { \
+ if((obj) != NULL) \
+ { \
+ V0((obj),Destruct)(); \
+ V0((obj),Delete)(); \
+ } \
+} while(0)
#ifdef __cplusplus
@@ -343,8 +372,8 @@ struct Hrtf;
#define MIN_OUTPUT_RATE (8000)
-// Find the next power-of-2 for non-power-of-2 numbers.
-static __inline ALuint NextPowerOf2(ALuint value)
+/* Find the next power-of-2 for non-power-of-2 numbers. */
+inline ALuint NextPowerOf2(ALuint value)
{
if(value > 0)
{
@@ -360,7 +389,7 @@ static __inline ALuint NextPowerOf2(ALuint value)
/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero
* mode. */
-static __inline ALint fastf2i(ALfloat f)
+inline ALint fastf2i(ALfloat f)
{
#ifdef HAVE_LRINTF
return lrintf(f);
@@ -376,7 +405,7 @@ static __inline ALint fastf2i(ALfloat f)
/* Fast float-to-uint conversion. Assumes the FPU is already in round-to-zero
* mode. */
-static __inline ALuint fastf2u(ALfloat f)
+inline ALuint fastf2u(ALfloat f)
{ return fastf2i(f); }
@@ -399,26 +428,9 @@ typedef struct {
ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
ALCuint (*AvailableSamples)(ALCdevice*);
- void (*Lock)(ALCdevice*);
- void (*Unlock)(ALCdevice*);
-
ALint64 (*GetLatency)(ALCdevice*);
} BackendFuncs;
-struct BackendInfo {
- const char *name;
- ALCboolean (*Init)(BackendFuncs*);
- void (*Deinit)(void);
- void (*Probe)(enum DevProbe);
- BackendFuncs Funcs;
-};
-
-ALCboolean alc_alsa_init(BackendFuncs *func_list);
-void alc_alsa_deinit(void);
-void alc_alsa_probe(enum DevProbe type);
-ALCboolean alc_oss_init(BackendFuncs *func_list);
-void alc_oss_deinit(void);
-void alc_oss_probe(enum DevProbe type);
ALCboolean alc_solaris_init(BackendFuncs *func_list);
void alc_solaris_deinit(void);
void alc_solaris_probe(enum DevProbe type);
@@ -440,21 +452,17 @@ void alc_pa_probe(enum DevProbe type);
ALCboolean alc_wave_init(BackendFuncs *func_list);
void alc_wave_deinit(void);
void alc_wave_probe(enum DevProbe type);
-ALCboolean alc_pulse_init(BackendFuncs *func_list);
-void alc_pulse_deinit(void);
-void alc_pulse_probe(enum DevProbe type);
ALCboolean alc_ca_init(BackendFuncs *func_list);
void alc_ca_deinit(void);
void alc_ca_probe(enum DevProbe type);
ALCboolean alc_opensl_init(BackendFuncs *func_list);
void alc_opensl_deinit(void);
void alc_opensl_probe(enum DevProbe type);
-ALCboolean alc_null_init(BackendFuncs *func_list);
-void alc_null_deinit(void);
-void alc_null_probe(enum DevProbe type);
-ALCboolean alc_loopback_init(BackendFuncs *func_list);
-void alc_loopback_deinit(void);
-void alc_loopback_probe(enum DevProbe type);
+ALCboolean alc_qsa_init(BackendFuncs *func_list);
+void alc_qsa_deinit(void);
+void alc_qsa_probe(enum DevProbe type);
+
+struct ALCbackend;
enum DistanceModel {
@@ -520,8 +528,7 @@ enum DevFmtChannels {
ALuint BytesFromDevFmt(enum DevFmtType type);
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans);
-static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans,
- enum DevFmtType type)
+inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
{
return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type);
}
@@ -546,15 +553,8 @@ enum DeviceType {
* more memory, while smaller values may need more iterations. The value needs
* to be a sensible size, however, as it constrains the max stepping value used
* for mixing, as well as the maximum number of samples per mixing iteration.
- *
- * The mixer requires being able to do two samplings per mixing loop. With the
- * cubic resampler (which requires 3 padding samples), this limits a 2048
- * buffer size to about 2044. This means that buffer_freq*source_pitch cannot
- * exceed device_freq*2044 for a 32-bit buffer.
*/
-#ifndef BUFFERSIZE
-#define BUFFERSIZE 2048
-#endif
+#define BUFFERSIZE (2048u)
struct ALCdevice_struct
@@ -564,8 +564,6 @@ struct ALCdevice_struct
ALCboolean Connected;
enum DeviceType Type;
- CRITICAL_SECTION Mutex;
-
ALuint Frequency;
ALuint UpdateSize;
ALuint NumUpdates;
@@ -594,6 +592,21 @@ struct ALCdevice_struct
// Map of Filters for this device
UIntMap FilterMap;
+ // Map of Soundfonts for this device
+ UIntMap SfontMap;
+
+ // Map of Presets for this device
+ UIntMap PresetMap;
+
+ // Map of Fontsounds for this device
+ UIntMap FontsoundMap;
+
+ /* Default soundfont (accessible as ID 0) */
+ struct ALsoundfont *DefaultSfont;
+
+ /* MIDI synth engine */
+ struct MidiSynth *Synth;
+
/* HRTF filter tables */
const struct Hrtf *Hrtf;
@@ -626,37 +639,29 @@ struct ALCdevice_struct
// Contexts created on this device
ALCcontext *volatile ContextList;
+ struct ALCbackend *Backend;
+
BackendFuncs *Funcs;
void *ExtraData; // For the backend's use
ALCdevice *volatile next;
};
-#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
-#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a)))
-#define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a)))
-#define ALCdevice_StartPlayback(a) ((a)->Funcs->StartPlayback((a)))
-#define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a)))
-#define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b)))
-#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a)))
-#define ALCdevice_StartCapture(a) ((a)->Funcs->StartCapture((a)))
-#define ALCdevice_StopCapture(a) ((a)->Funcs->StopCapture((a)))
-#define ALCdevice_CaptureSamples(a,b,c) ((a)->Funcs->CaptureSamples((a), (b), (c)))
-#define ALCdevice_AvailableSamples(a) ((a)->Funcs->AvailableSamples((a)))
-#define ALCdevice_Lock(a) ((a)->Funcs->Lock((a)))
-#define ALCdevice_Unlock(a) ((a)->Funcs->Unlock((a)))
-#define ALCdevice_GetLatency(a) ((a)->Funcs->GetLatency((a)))
-
// Frequency was requested by the app or config file
#define DEVICE_FREQUENCY_REQUEST (1<<1)
// Channel configuration was requested by the config file
#define DEVICE_CHANNELS_REQUEST (1<<2)
// Sample type was requested by the config file
#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3)
+// HRTF was requested by the app
+#define DEVICE_HRTF_REQUEST (1<<4)
// Stereo sources cover 120-degree angles around +/-90
#define DEVICE_WIDE_STEREO (1<<16)
+// Specifies if the DSP is paused at user request
+#define DEVICE_PAUSED (1<<30)
+
// Specifies if the device is currently running
#define DEVICE_RUNNING (1<<31)
@@ -664,12 +669,9 @@ struct ALCdevice_struct
#define INVALID_OFFSET (~0u)
-#define LookupBuffer(m, k) ((struct ALbuffer*)LookupUIntMapKey(&(m)->BufferMap, (k)))
-#define LookupEffect(m, k) ((struct ALeffect*)LookupUIntMapKey(&(m)->EffectMap, (k)))
-#define LookupFilter(m, k) ((struct ALfilter*)LookupUIntMapKey(&(m)->FilterMap, (k)))
-#define RemoveBuffer(m, k) ((struct ALbuffer*)RemoveUIntMapKey(&(m)->BufferMap, (k)))
-#define RemoveEffect(m, k) ((struct ALeffect*)RemoveUIntMapKey(&(m)->EffectMap, (k)))
-#define RemoveFilter(m, k) ((struct ALfilter*)RemoveUIntMapKey(&(m)->FilterMap, (k)))
+/* Must be less than 15 characters (16 including terminating null) for
+ * compatibility with pthread_setname_np limitations. */
+#define MIXER_THREAD_NAME "alsoft-mixer"
struct ALCcontext_struct
@@ -707,12 +709,6 @@ struct ALCcontext_struct
ALCcontext *volatile next;
};
-#define LookupSource(m, k) ((struct ALsource*)LookupUIntMapKey(&(m)->SourceMap, (k)))
-#define LookupEffectSlot(m, k) ((struct ALeffectslot*)LookupUIntMapKey(&(m)->EffectSlotMap, (k)))
-#define RemoveSource(m, k) ((struct ALsource*)RemoveUIntMapKey(&(m)->SourceMap, (k)))
-#define RemoveEffectSlot(m, k) ((struct ALeffectslot*)RemoveUIntMapKey(&(m)->EffectSlotMap, (k)))
-
-
ALCcontext *GetContextRef(void);
void ALCcontext_IncRef(ALCcontext *context);
@@ -721,13 +717,16 @@ void ALCcontext_DecRef(ALCcontext *context);
void AppendAllDevicesList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
-void ALCdevice_LockDefault(ALCdevice *device);
-void ALCdevice_UnlockDefault(ALCdevice *device);
ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device);
-static __inline void LockContext(ALCcontext *context)
+void ALCdevice_Lock(ALCdevice *device);
+void ALCdevice_Unlock(ALCdevice *device);
+ALint64 ALCdevice_GetLatency(ALCdevice *device);
+
+inline void LockContext(ALCcontext *context)
{ ALCdevice_Lock(context->Device); }
-static __inline void UnlockContext(ALCcontext *context)
+
+inline void UnlockContext(ALCcontext *context)
{ ALCdevice_Unlock(context->Device); }
@@ -735,8 +734,13 @@ void *al_malloc(size_t alignment, size_t size);
void *al_calloc(size_t alignment, size_t size);
void al_free(void *ptr);
+
typedef struct {
+#ifdef HAVE_FENV_H
+ DERIVE_FROM_TYPE(fenv_t);
+#else
int state;
+#endif
#ifdef HAVE_SSE
int sse_state;
#endif
@@ -744,8 +748,6 @@ typedef struct {
void SetMixerFPUMode(FPUCtl *ctl);
void RestoreFPUMode(const FPUCtl *ctl);
-ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
-ALuint StopThread(ALvoid *thread);
typedef struct RingBuffer RingBuffer;
RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
@@ -779,16 +781,23 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
const struct Hrtf *GetHrtf(ALCdevice *device);
+void FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate);
void FreeHrtfs(void);
-ALuint GetHrtfIrSize (const struct Hrtf *Hrtf);
+ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
-void al_print(const char *type, const char *func, const char *fmt, ...) PRINTF_STYLE(3,4);
-#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__)
extern FILE *LogFile;
+
+#ifdef __GNUC__
+#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
+#else
+void al_print(const char *type, const char *func, const char *fmt, ...) PRINTF_STYLE(3,4);
+#define AL_PRINT(T, MSG, ...) al_print((T), __FUNCTION__, MSG, __VA_ARGS__)
+#endif
+
enum LogLevel {
NoLog,
LogError,
@@ -825,57 +834,17 @@ extern ALint RTPrioLevel;
extern ALuint CPUCapFlags;
enum {
CPU_CAP_SSE = 1<<0,
- CPU_CAP_NEON = 1<<1,
+ CPU_CAP_SSE2 = 1<<1,
+ CPU_CAP_NEON = 1<<2,
};
void FillCPUCaps(ALuint capfilter);
-/**
- * Starts a try block. Must not be nested within another try block within the
- * same function.
- */
-#define al_try do { \
- int _al_err=0; \
-_al_try_label: \
- if(_al_err == 0)
-/**
- * After a try or another catch block, runs the next block if the given value
- * was thrown.
- */
-#define al_catch(val) else if(_al_err == (val))
-/**
- * After a try or catch block, runs the next block for any value thrown and not
- * caught.
- */
-#define al_catchany() else
-/** Marks the end of the final catch (or the try) block. */
-#define al_endtry } while(0)
-
-/**
- * The given integer value is "thrown" so as to be caught by a catch block.
- * Must be called in a try block within the same function. The value must not
- * be 0.
- */
-#define al_throw(e) do { \
- _al_err = (e); \
- assert(_al_err != 0); \
- goto _al_try_label; \
-} while(0)
-/** Sets an AL error on the given context, before throwing the error code. */
-#define al_throwerr(ctx, err) do { \
- alSetError((ctx), (err)); \
- al_throw((err)); \
-} while(0)
+/* Small hack to use a pointer-to-array type as a normal argument type.
+ * Shouldn't be used directly. */
+typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
-/**
- * Throws an AL_INVALID_VALUE error with the given ctx if the given condition
- * is false.
- */
-#define CHECK_VALUE(ctx, cond) do { \
- if(!(cond)) \
- al_throwerr((ctx), AL_INVALID_VALUE); \
-} while(0)
#ifdef __cplusplus
}
diff --git a/OpenAL32/Include/alMidi.h b/OpenAL32/Include/alMidi.h
new file mode 100644
index 00000000..24e6675f
--- /dev/null
+++ b/OpenAL32/Include/alMidi.h
@@ -0,0 +1,166 @@
+#ifndef ALMIDI_H
+#define ALMIDI_H
+
+#include "alMain.h"
+#include "atomic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALsfmodulator {
+ struct {
+ ALenum Input;
+ ALenum Type;
+ ALenum Form;
+ } Source[2];
+ ALint Amount;
+ ALenum TransformOp;
+ ALenum Dest;
+} ALsfmodulator;
+
+typedef struct ALenvelope {
+ ALint DelayTime;
+ ALint AttackTime;
+ ALint HoldTime;
+ ALint DecayTime;
+ ALint SustainAttn;
+ ALint ReleaseTime;
+ ALint KeyToHoldTime;
+ ALint KeyToDecayTime;
+} ALenvelope;
+
+
+typedef struct ALfontsound {
+ volatile RefCount ref;
+
+ ALint MinKey, MaxKey;
+ ALint MinVelocity, MaxVelocity;
+
+ ALint ModLfoToPitch;
+ ALint VibratoLfoToPitch;
+ ALint ModEnvToPitch;
+
+ ALint FilterCutoff;
+ ALint FilterQ;
+ ALint ModLfoToFilterCutoff;
+ ALint ModEnvToFilterCutoff;
+ ALint ModLfoToVolume;
+
+ ALint ChorusSend;
+ ALint ReverbSend;
+
+ ALint Pan;
+
+ struct {
+ ALint Delay;
+ ALint Frequency;
+ } ModLfo;
+ struct {
+ ALint Delay;
+ ALint Frequency;
+ } VibratoLfo;
+
+ ALenvelope ModEnv;
+ ALenvelope VolEnv;
+
+ ALint Attenuation;
+
+ ALint CoarseTuning;
+ ALint FineTuning;
+
+ ALenum LoopMode;
+
+ ALint TuningScale;
+
+ ALint ExclusiveClass;
+
+ ALuint Start;
+ ALuint End;
+ ALuint LoopStart;
+ ALuint LoopEnd;
+ ALuint SampleRate;
+ ALubyte PitchKey;
+ ALbyte PitchCorrection;
+ ALenum SampleType;
+ struct ALfontsound *Link;
+
+ UIntMap ModulatorMap;
+
+ ALuint id;
+} ALfontsound;
+
+void ALfontsound_Destruct(ALfontsound *self);
+void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value);
+void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value);
+
+ALfontsound *NewFontsound(ALCcontext *context);
+
+inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id)
+{ return (struct ALfontsound*)LookupUIntMapKey(&device->FontsoundMap, id); }
+inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id)
+{ return (struct ALfontsound*)RemoveUIntMapKey(&device->FontsoundMap, id); }
+
+inline struct ALsfmodulator *LookupModulator(ALfontsound *sound, ALuint id)
+{ return (struct ALsfmodulator*)LookupUIntMapKey(&sound->ModulatorMap, id); }
+inline struct ALsfmodulator *RemoveModulator(ALfontsound *sound, ALuint id)
+{ return (struct ALsfmodulator*)RemoveUIntMapKey(&sound->ModulatorMap, id); }
+
+void ReleaseALFontsounds(ALCdevice *device);
+
+
+typedef struct ALsfpreset {
+ volatile RefCount ref;
+
+ ALint Preset; /* a.k.a. MIDI program number */
+ ALint Bank; /* MIDI bank 0...127, or percussion (bank 128) */
+
+ ALfontsound **Sounds;
+ ALsizei NumSounds;
+
+ ALuint id;
+} ALsfpreset;
+
+ALsfpreset *NewPreset(ALCcontext *context);
+void DeletePreset(ALsfpreset *preset, ALCdevice *device);
+
+inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id)
+{ return (struct ALsfpreset*)LookupUIntMapKey(&device->PresetMap, id); }
+inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id)
+{ return (struct ALsfpreset*)RemoveUIntMapKey(&device->PresetMap, id); }
+
+void ReleaseALPresets(ALCdevice *device);
+
+
+typedef struct ALsoundfont {
+ volatile RefCount ref;
+
+ ALsfpreset **Presets;
+ ALsizei NumPresets;
+
+ ALshort *Samples;
+ ALint NumSamples;
+
+ RWLock Lock;
+ volatile ALenum Mapped;
+
+ ALuint id;
+} ALsoundfont;
+
+void ALsoundfont_Construct(ALsoundfont *self);
+void ALsoundfont_Destruct(ALsoundfont *self);
+ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
+void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
+
+inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id)
+{ return (struct ALsoundfont*)LookupUIntMapKey(&device->SfontMap, id); }
+inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id)
+{ return (struct ALsoundfont*)RemoveUIntMapKey(&device->SfontMap, id); }
+
+void ReleaseALSoundfonts(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ALMIDI_H */
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
index d8ffc9aa..31a0d229 100644
--- a/OpenAL32/Include/alSource.h
+++ b/OpenAL32/Include/alSource.h
@@ -6,6 +6,7 @@
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
+#include "alBuffer.h"
#ifdef __cplusplus
extern "C" {
@@ -21,8 +22,7 @@ extern const ALsizei ResamplerPadding[ResamplerMax];
extern const ALsizei ResamplerPrePadding[ResamplerMax];
-typedef struct ALbufferlistitem
-{
+typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
struct ALbufferlistitem *next;
struct ALbufferlistitem *prev;
@@ -31,17 +31,17 @@ typedef struct ALbufferlistitem
typedef struct HrtfState {
ALboolean Moving;
ALuint Counter;
- ALIGN(16) ALfloat History[MaxChannels][SRC_HISTORY_LENGTH];
- ALIGN(16) ALfloat Values[MaxChannels][HRIR_LENGTH][2];
+ ALIGN(16) ALfloat History[MAX_INPUT_CHANNELS][SRC_HISTORY_LENGTH];
+ ALIGN(16) ALfloat Values[MAX_INPUT_CHANNELS][HRIR_LENGTH][2];
ALuint Offset;
} HrtfState;
typedef struct HrtfParams {
ALfloat Gain;
ALfloat Dir[3];
- ALIGN(16) ALfloat Coeffs[MaxChannels][HRIR_LENGTH][2];
+ ALIGN(16) ALfloat Coeffs[MAX_INPUT_CHANNELS][HRIR_LENGTH][2];
ALIGN(16) ALfloat CoeffStep[HRIR_LENGTH][2];
- ALuint Delay[MaxChannels][2];
+ ALuint Delay[MAX_INPUT_CHANNELS][2];
ALint DelayStep[2];
ALuint IrSize;
} HrtfParams;
@@ -59,23 +59,21 @@ typedef struct DirectParams {
/* A mixing matrix. First subscript is the channel number of the input data
* (regardless of channel configuration) and the second is the channel
* target (eg. FrontLeft). Not used with HRTF. */
- ALfloat Gains[MaxChannels][MaxChannels];
+ ALfloat Gains[MAX_INPUT_CHANNELS][MaxChannels];
- /* A low-pass filter, using 2 chained one-pole filters. */
- FILTER iirFilter;
- ALfloat history[MaxChannels*2];
+ ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} DirectParams;
typedef struct SendParams {
- struct ALeffectslot *Slot;
+ ALfloat (*OutBuffer)[BUFFERSIZE];
+ ALfloat *ClickRemoval;
+ ALfloat *PendingClicks;
/* Gain control, which applies to all input channels to a single (mono)
* output buffer. */
ALfloat Gain;
- /* A low-pass filter, using 2 chained one-pole filters. */
- FILTER iirFilter;
- ALfloat history[MaxChannels*2];
+ ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} SendParams;
@@ -178,6 +176,11 @@ typedef struct ALsource
} ALsource;
#define ALsource_Update(s,a) ((s)->Update(s,a))
+inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
+{ return (struct ALsource*)LookupUIntMapKey(&context->SourceMap, id); }
+inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
+{ return (struct ALsource*)RemoveUIntMapKey(&context->SourceMap, id); }
+
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
ALboolean ApplyOffset(ALsource *Source);
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index 01d3ca29..d88e860c 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -13,13 +13,17 @@
#endif
-#define F_PI (3.14159265358979323846f) /* pi */
-#define F_PI_2 (1.57079632679489661923f) /* pi/2 */
+#define F_PI (3.14159265358979323846f)
+#define F_PI_2 (1.57079632679489661923f)
+#define F_2PI (6.28318530717958647692f)
#ifndef FLT_EPSILON
#define FLT_EPSILON (1.19209290e-07f)
#endif
+#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f))
+#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
+
#ifdef __cplusplus
extern "C" {
@@ -31,18 +35,20 @@ struct DirectParams;
struct SendParams;
typedef void (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment,
- ALfloat *RESTRICT dst, ALuint dstlen);
+ ALfloat *restrict dst, ALuint dstlen);
typedef ALvoid (*DryMixerFunc)(const struct DirectParams *params,
- const ALfloat *RESTRICT data, ALuint srcchan,
+ const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo,
ALuint BufferSize);
typedef ALvoid (*WetMixerFunc)(const struct SendParams *params,
- const ALfloat *RESTRICT data,
+ const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo,
ALuint BufferSize);
+#define GAIN_SILENCE_THRESHOLD (0.00001f)
+
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
@@ -51,47 +57,54 @@ typedef ALvoid (*WetMixerFunc)(const struct SendParams *params,
#define FRACTIONMASK (FRACTIONONE-1)
-static __inline ALfloat minf(ALfloat a, ALfloat b)
+inline ALfloat minf(ALfloat a, ALfloat b)
{ return ((a > b) ? b : a); }
-static __inline ALfloat maxf(ALfloat a, ALfloat b)
+inline ALfloat maxf(ALfloat a, ALfloat b)
{ return ((a > b) ? a : b); }
-static __inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max)
+inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max)
{ return minf(max, maxf(min, val)); }
-static __inline ALuint minu(ALuint a, ALuint b)
+inline ALdouble mind(ALdouble a, ALdouble b)
+{ return ((a > b) ? b : a); }
+inline ALdouble maxd(ALdouble a, ALdouble b)
+{ return ((a > b) ? a : b); }
+inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max)
+{ return mind(max, maxd(min, val)); }
+
+inline ALuint minu(ALuint a, ALuint b)
{ return ((a > b) ? b : a); }
-static __inline ALuint maxu(ALuint a, ALuint b)
+inline ALuint maxu(ALuint a, ALuint b)
{ return ((a > b) ? a : b); }
-static __inline ALuint clampu(ALuint val, ALuint min, ALuint max)
+inline ALuint clampu(ALuint val, ALuint min, ALuint max)
{ return minu(max, maxu(min, val)); }
-static __inline ALint mini(ALint a, ALint b)
+inline ALint mini(ALint a, ALint b)
{ return ((a > b) ? b : a); }
-static __inline ALint maxi(ALint a, ALint b)
+inline ALint maxi(ALint a, ALint b)
{ return ((a > b) ? a : b); }
-static __inline ALint clampi(ALint val, ALint min, ALint max)
+inline ALint clampi(ALint val, ALint min, ALint max)
{ return mini(max, maxi(min, val)); }
-static __inline ALint64 mini64(ALint64 a, ALint64 b)
+inline ALint64 mini64(ALint64 a, ALint64 b)
{ return ((a > b) ? b : a); }
-static __inline ALint64 maxi64(ALint64 a, ALint64 b)
+inline ALint64 maxi64(ALint64 a, ALint64 b)
{ return ((a > b) ? a : b); }
-static __inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max)
+inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max)
{ return mini64(max, maxi64(min, val)); }
-static __inline ALuint64 minu64(ALuint64 a, ALuint64 b)
+inline ALuint64 minu64(ALuint64 a, ALuint64 b)
{ return ((a > b) ? b : a); }
-static __inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
+inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
{ return ((a > b) ? a : b); }
-static __inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
+inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
-static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
+inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
-static __inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu)
+inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu)
{
ALfloat mu2 = mu*mu;
ALfloat a0 = -0.5f*val0 + 1.5f*val1 + -1.5f*val2 + 0.5f*val3;
@@ -105,7 +118,24 @@ static __inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat
ALvoid aluInitPanning(ALCdevice *Device);
-ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains);
+/**
+ * ComputeAngleGains
+ *
+ * Sets channel gains based on a given source's angle and its half-width. The
+ * angle and hwidth parameters are in radians.
+ */
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]);
+
+/**
+ * SetGains
+ *
+ * Helper to set the appropriate channels to the specified gain.
+ */
+inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels])
+{
+ ComputeAngleGains(device, 0.0f, F_PI, ingain, gains);
+}
+
ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
diff --git a/OpenAL32/Include/threads.h b/OpenAL32/Include/threads.h
new file mode 100644
index 00000000..26493101
--- /dev/null
+++ b/OpenAL32/Include/threads.h
@@ -0,0 +1,14 @@
+#ifndef AL_THREADS_H
+#define AL_THREADS_H
+
+#include "alMain.h"
+
+struct althread_info;
+typedef struct althread_info* althread_t;
+
+ALboolean StartThread(althread_t *out, ALuint (*func)(ALvoid*), ALvoid *ptr);
+ALuint StopThread(althread_t thread);
+
+void SetThreadName(const char *name);
+
+#endif /* AL_THREADS_H */
diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c
index 230fe5fc..aa071de2 100644
--- a/OpenAL32/alAuxEffectSlot.c
+++ b/OpenAL32/alAuxEffectSlot.c
@@ -32,538 +32,491 @@
#include "alSource.h"
+extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
+extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
+
static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots);
static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot);
+static UIntMap EffectStateFactoryMap;
+static inline ALeffectStateFactory *getFactoryByType(ALenum type)
+{
+ ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
+ if(getFactory != NULL)
+ return getFactory();
+ return NULL;
+}
+
+
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
- ALCcontext *Context;
- ALsizei cur = 0;
+ ALCcontext *context;
+ ALsizei cur;
+ ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(cur = 0;cur < n;cur++)
{
- ALenum err;
-
- CHECK_VALUE(Context, n >= 0);
- for(cur = 0;cur < n;cur++)
+ ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
+ err = AL_OUT_OF_MEMORY;
+ if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
{
- ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
- err = AL_OUT_OF_MEMORY;
- if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
- {
- al_free(slot);
- al_throwerr(Context, err);
- break;
- }
-
- err = NewThunkEntry(&slot->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->id, slot);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(slot->id);
- ALeffectState_Destroy(slot->EffectState);
- al_free(slot);
-
- al_throwerr(Context, err);
- }
-
- effectslots[cur] = slot->id;
+ al_free(slot);
+ alDeleteAuxiliaryEffectSlots(cur, effectslots);
+ SET_ERROR_AND_GOTO(context, err, done);
}
- err = AddEffectSlotArray(Context, n, effectslots);
+
+ err = NewThunkEntry(&slot->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
+ {
+ FreeThunkEntry(slot->id);
+ DELETE_OBJ(slot->EffectState);
+ al_free(slot);
+
+ alDeleteAuxiliaryEffectSlots(cur, effectslots);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ effectslots[cur] = slot->id;
}
- al_catchany()
+ err = AddEffectSlotArray(context, n, effectslots);
+ if(err != AL_NO_ERROR)
{
- if(cur > 0)
- alDeleteAuxiliaryEffectSlots(cur, effectslots);
+ alDeleteAuxiliaryEffectSlots(cur, effectslots);
+ SET_ERROR_AND_GOTO(context, err, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
{
- ALCcontext *Context;
+ ALCcontext *context;
ALeffectslot *slot;
ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < n;i++)
{
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if((slot=LookupEffectSlot(Context, effectslots[i])) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- if(slot->ref != 0)
- al_throwerr(Context, AL_INVALID_OPERATION);
- }
+ if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(slot->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
- // All effectslots are valid
- for(i = 0;i < n;i++)
- {
- if((slot=RemoveEffectSlot(Context, effectslots[i])) == NULL)
- continue;
- FreeThunkEntry(slot->id);
+ // All effectslots are valid
+ for(i = 0;i < n;i++)
+ {
+ if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
+ continue;
+ FreeThunkEntry(slot->id);
- RemoveEffectSlotArray(Context, slot);
- ALeffectState_Destroy(slot->EffectState);
+ RemoveEffectSlotArray(context, slot);
+ DELETE_OBJ(slot->EffectState);
- memset(slot, 0, sizeof(*slot));
- al_free(slot);
- }
+ memset(slot, 0, sizeof(*slot));
+ al_free(slot);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
{
- ALCcontext *Context;
- ALboolean result;
+ ALCcontext *context;
+ ALboolean ret;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE);
+ ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
- return result;
+ return ret;
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
{
- ALCcontext *Context;
- ALeffectslot *Slot;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALeffectslot *slot;
ALeffect *effect = NULL;
ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ device = context->Device;
+ if((slot=LookupEffectSlot(context, effectslot)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- ALCdevice *device = Context->Device;
- if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- case AL_EFFECTSLOT_EFFECT:
- CHECK_VALUE(Context, value == 0 || (effect=LookupEffect(device, value)) != NULL);
+ case AL_EFFECTSLOT_EFFECT:
+ effect = (value ? LookupEffect(device, value) : NULL);
+ if(!(value == 0 || effect != NULL))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- err = InitializeEffect(device, Slot, effect);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- Context->UpdateSources = AL_TRUE;
- break;
+ err = InitializeEffect(device, slot, effect);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ context->UpdateSources = AL_TRUE;
+ break;
- case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
- CHECK_VALUE(Context, value == AL_TRUE || value == AL_FALSE);
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ if(!(value == AL_TRUE || value == AL_FALSE))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Slot->AuxSendAuto = value;
- Context->UpdateSources = AL_TRUE;
- break;
+ slot->AuxSendAuto = value;
+ context->UpdateSources = AL_TRUE;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_EFFECTSLOT_EFFECT:
- case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
- alAuxiliaryEffectSloti(effectslot, param, values[0]);
- return;
+ case AL_EFFECTSLOT_EFFECT:
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ alAuxiliaryEffectSloti(effectslot, param, values[0]);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(LookupEffectSlot(context, effectslot) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if(LookupEffectSlot(Context, effectslot) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
{
- ALCcontext *Context;
- ALeffectslot *Slot;
+ ALCcontext *context;
+ ALeffectslot *slot;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if((slot=LookupEffectSlot(context, effectslot)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- case AL_EFFECTSLOT_GAIN:
- CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
+ case AL_EFFECTSLOT_GAIN:
+ if(!(value >= 0.0f && value <= 1.0f))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Slot->Gain = value;
- Slot->NeedsUpdate = AL_TRUE;
- break;
+ slot->Gain = value;
+ slot->NeedsUpdate = AL_TRUE;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_EFFECTSLOT_GAIN:
- alAuxiliaryEffectSlotf(effectslot, param, values[0]);
- return;
+ case AL_EFFECTSLOT_GAIN:
+ alAuxiliaryEffectSlotf(effectslot, param, values[0]);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(LookupEffectSlot(context, effectslot) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if(LookupEffectSlot(Context, effectslot) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
{
- ALCcontext *Context;
- ALeffectslot *Slot;
+ ALCcontext *context;
+ ALeffectslot *slot;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if((slot=LookupEffectSlot(context, effectslot)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- case AL_EFFECTSLOT_EFFECT:
- *value = Slot->effect.id;
- break;
-
- case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
- *value = Slot->AuxSendAuto;
- break;
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ *value = slot->AuxSendAuto;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_EFFECTSLOT_EFFECT:
- case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
- alGetAuxiliaryEffectSloti(effectslot, param, values);
- return;
+ case AL_EFFECTSLOT_EFFECT:
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ alGetAuxiliaryEffectSloti(effectslot, param, values);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(LookupEffectSlot(context, effectslot) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if(LookupEffectSlot(Context, effectslot) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
{
- ALCcontext *Context;
- ALeffectslot *Slot;
+ ALCcontext *context;
+ ALeffectslot *slot;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if((slot=LookupEffectSlot(context, effectslot)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- case AL_EFFECTSLOT_GAIN:
- *value = Slot->Gain;
- break;
+ case AL_EFFECTSLOT_GAIN:
+ *value = slot->Gain;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_EFFECTSLOT_GAIN:
- alGetAuxiliaryEffectSlotf(effectslot, param, values);
- return;
+ case AL_EFFECTSLOT_GAIN:
+ alGetAuxiliaryEffectSlotf(effectslot, param, values);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(LookupEffectSlot(context, effectslot) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
{
- if(LookupEffectSlot(Context, effectslot) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
-
- ALCcontext_DecRef(Context);
-}
-
-
-static ALvoid NoneDestroy(ALeffectState *State)
-{ free(State); }
-static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
-{
- return AL_TRUE;
- (void)State;
- (void)Device;
-}
-static ALvoid NoneUpdate(ALeffectState *State, ALCdevice *Device, const ALeffectslot *Slot)
-{
- (void)State;
- (void)Device;
- (void)Slot;
-}
-static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
-{
- (void)State;
- (void)SamplesToDo;
- (void)SamplesIn;
- (void)SamplesOut;
-}
-ALeffectState *NoneCreate(void)
-{
- ALeffectState *state;
-
- state = calloc(1, sizeof(*state));
- if(!state)
- return NULL;
-
- state->Destroy = NoneDestroy;
- state->DeviceUpdate = NoneDeviceUpdate;
- state->Update = NoneUpdate;
- state->Process = NoneProcess;
- return state;
+done:
+ ALCcontext_DecRef(context);
}
-static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
+static ALvoid RemoveEffectSlotArray(ALCcontext *context, ALeffectslot *slot)
{
ALeffectslot **slotlist, **slotlistend;
- LockContext(Context);
- slotlist = Context->ActiveEffectSlots;
- slotlistend = slotlist + Context->ActiveEffectSlotCount;
+ LockContext(context);
+ slotlist = context->ActiveEffectSlots;
+ slotlistend = slotlist + context->ActiveEffectSlotCount;
while(slotlist != slotlistend)
{
if(*slotlist == slot)
{
*slotlist = *(--slotlistend);
- Context->ActiveEffectSlotCount--;
+ context->ActiveEffectSlotCount--;
break;
}
slotlist++;
}
- UnlockContext(Context);
+ UnlockContext(context);
}
-static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots)
+static ALenum AddEffectSlotArray(ALCcontext *context, ALsizei count, const ALuint *slots)
{
ALsizei i;
- LockContext(Context);
- if(count > Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
+ LockContext(context);
+ if(count > context->MaxActiveEffectSlots-context->ActiveEffectSlotCount)
{
ALsizei newcount;
void *temp = NULL;
- newcount = Context->MaxActiveEffectSlots ? (Context->MaxActiveEffectSlots<<1) : 1;
- if(newcount > Context->MaxActiveEffectSlots)
- temp = realloc(Context->ActiveEffectSlots,
- newcount * sizeof(*Context->ActiveEffectSlots));
+ newcount = context->MaxActiveEffectSlots ? (context->MaxActiveEffectSlots<<1) : 1;
+ if(newcount > context->MaxActiveEffectSlots)
+ temp = realloc(context->ActiveEffectSlots,
+ newcount * sizeof(*context->ActiveEffectSlots));
if(!temp)
{
- UnlockContext(Context);
+ UnlockContext(context);
return AL_OUT_OF_MEMORY;
}
- Context->ActiveEffectSlots = temp;
- Context->MaxActiveEffectSlots = newcount;
+ context->ActiveEffectSlots = temp;
+ context->MaxActiveEffectSlots = newcount;
}
for(i = 0;i < count;i++)
{
- ALeffectslot *slot = LookupEffectSlot(Context, slots[i]);
+ ALeffectslot *slot = LookupEffectSlot(context, slots[i]);
assert(slot != NULL);
- Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot;
+ context->ActiveEffectSlots[context->ActiveEffectSlotCount++] = slot;
}
- UnlockContext(Context);
+ UnlockContext(context);
return AL_NO_ERROR;
}
+
+void InitEffectFactoryMap(void)
+{
+ InitUIntMap(&EffectStateFactoryMap, ~0);
+
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
+ InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
+}
+
+void DeinitEffectFactoryMap(void)
+{
+ ResetUIntMap(&EffectStateFactoryMap);
+}
+
+
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
- ALeffectState *State = NULL;
- ALenum err = AL_NO_ERROR;
+ ALeffectStateFactory *factory;
- ALCdevice_Lock(Device);
- if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
- {
- State = NoneCreate();
- if(!State) err = AL_OUT_OF_MEMORY;
- }
- else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
- {
- if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
- {
- State = ReverbCreate();
- if(!State) err = AL_OUT_OF_MEMORY;
- }
- }
- else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
- {
- State = EchoCreate();
- if(!State) err = AL_OUT_OF_MEMORY;
- }
- else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
- {
- State = ModulatorCreate();
- if(!State) err = AL_OUT_OF_MEMORY;
- }
- else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+ if(newtype != EffectSlot->EffectType)
{
- if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+ ALeffectState *State;
+ FPUCtl oldMode;
+
+ factory = getFactoryByType(newtype);
+ if(!factory)
{
- State = DedicatedCreate();
- if(!State) err = AL_OUT_OF_MEMORY;
+ ERR("Failed to find factory for effect type 0x%04x\n", newtype);
+ return AL_INVALID_ENUM;
}
- }
-
- if(err != AL_NO_ERROR)
- {
- ALCdevice_Unlock(Device);
- return err;
- }
+ State = V0(factory,create)();
+ if(!State)
+ return AL_OUT_OF_MEMORY;
- if(State)
- {
- FPUCtl oldMode;
SetMixerFPUMode(&oldMode);
- if(ALeffectState_DeviceUpdate(State, Device) == AL_FALSE)
+ ALCdevice_Lock(Device);
+ if(V(State,deviceUpdate)(Device) == AL_FALSE)
{
- RestoreFPUMode(&oldMode);
ALCdevice_Unlock(Device);
- ALeffectState_Destroy(State);
+ RestoreFPUMode(&oldMode);
+ DELETE_OBJ(State);
return AL_OUT_OF_MEMORY;
}
- State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
+ State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
if(!effect)
- memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
+ {
+ memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
+ EffectSlot->EffectType = AL_EFFECT_NULL;
+ }
else
- memcpy(&EffectSlot->effect, effect, sizeof(*effect));
+ {
+ memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
+ EffectSlot->EffectType = effect->type;
+ }
+
/* FIXME: This should be done asynchronously, but since the EffectState
* object was changed, it needs an update before its Process method can
* be called. */
EffectSlot->NeedsUpdate = AL_FALSE;
- ALeffectState_Update(EffectSlot->EffectState, Device, EffectSlot);
+ V(EffectSlot->EffectState,update)(Device, EffectSlot);
ALCdevice_Unlock(Device);
RestoreFPUMode(&oldMode);
- ALeffectState_Destroy(State);
+ DELETE_OBJ(State);
State = NULL;
}
else
{
- if(!effect)
- memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
- else
- memcpy(&EffectSlot->effect, effect, sizeof(*effect));
- ALCdevice_Unlock(Device);
- EffectSlot->NeedsUpdate = AL_TRUE;
+ if(effect)
+ {
+ ALCdevice_Lock(Device);
+ memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
+ ALCdevice_Unlock(Device);
+ EffectSlot->NeedsUpdate = AL_TRUE;
+ }
}
return AL_NO_ERROR;
@@ -572,9 +525,13 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
ALenum InitEffectSlot(ALeffectslot *slot)
{
- ALint i, c;
+ ALeffectStateFactory *factory;
+ ALuint i, c;
+
+ slot->EffectType = AL_EFFECT_NULL;
- if(!(slot->EffectState=NoneCreate()))
+ factory = getFactoryByType(AL_EFFECT_NULL);
+ if(!(slot->EffectState=V0(factory,create)()))
return AL_OUT_OF_MEMORY;
slot->Gain = 1.0;
@@ -600,7 +557,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
Context->EffectSlotMap.array[pos].value = NULL;
- ALeffectState_Destroy(temp->EffectState);
+ DELETE_OBJ(temp->EffectState);
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffectslot));
diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c
index 29f3e617..d9c91c2f 100644
--- a/OpenAL32/alBuffer.c
+++ b/OpenAL32/alBuffer.c
@@ -32,6 +32,11 @@
#include "alThunk.h"
+extern inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id);
+extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id);
+extern inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
+extern inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
+
static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data, ALboolean storesrc);
static void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len);
static ALboolean IsValidType(ALenum type);
@@ -182,287 +187,285 @@ static const char aLawCompressTable[128] = {
AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
{
- ALCcontext *Context;
- ALsizei cur = 0;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsizei cur = 0;
+ ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- ALenum err;
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- CHECK_VALUE(Context, n >= 0);
- for(cur = 0;cur < n;cur++)
+ device = context->Device;
+ for(cur = 0;cur < n;cur++)
+ {
+ ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
+ if(!buffer)
{
- ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
- if(!buffer)
- al_throwerr(Context, AL_OUT_OF_MEMORY);
- RWLockInit(&buffer->lock);
-
- err = NewThunkEntry(&buffer->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(buffer->id);
- memset(buffer, 0, sizeof(ALbuffer));
- free(buffer);
+ alDeleteBuffers(cur, buffers);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ }
+ RWLockInit(&buffer->lock);
- al_throwerr(Context, err);
- }
+ err = NewThunkEntry(&buffer->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
+ if(err != AL_NO_ERROR)
+ {
+ FreeThunkEntry(buffer->id);
+ memset(buffer, 0, sizeof(ALbuffer));
+ free(buffer);
- buffers[cur] = buffer->id;
- }
- }
- al_catchany()
- {
- if(cur > 0)
alDeleteBuffers(cur, buffers);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ buffers[cur] = buffer->id;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
ALbuffer *ALBuf;
ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(!buffers[i])
- continue;
-
- /* Check for valid Buffer ID */
- if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- if(ALBuf->ref != 0)
- al_throwerr(Context, AL_INVALID_OPERATION);
- }
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ if(!buffers[i])
+ continue;
+
+ /* Check for valid Buffer ID */
+ if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(ALBuf->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
- for(i = 0;i < n;i++)
- {
- if((ALBuf=RemoveBuffer(device, buffers[i])) == NULL)
- continue;
- FreeThunkEntry(ALBuf->id);
+ for(i = 0;i < n;i++)
+ {
+ if((ALBuf=RemoveBuffer(device, buffers[i])) == NULL)
+ continue;
+ FreeThunkEntry(ALBuf->id);
- free(ALBuf->data);
+ free(ALBuf->data);
- memset(ALBuf, 0, sizeof(*ALBuf));
- free(ALBuf);
- }
+ memset(ALBuf, 0, sizeof(*ALBuf));
+ free(ALBuf);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
{
- ALCcontext *Context;
- ALboolean result;
+ ALCcontext *context;
+ ALboolean ret;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- result = ((!buffer || LookupBuffer(Context->Device, buffer)) ?
- AL_TRUE : AL_FALSE);
+ ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
+ AL_TRUE : AL_FALSE);
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
- return result;
+ return ret;
}
AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
{
- enum UserFmtChannels SrcChannels;
- enum UserFmtType SrcType;
- ALCcontext *Context;
- ALuint FrameSize;
- ALenum NewFormat;
- ALbuffer *ALBuf;
+ enum UserFmtChannels srcchannels;
+ enum UserFmtType srctype;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALuint framesize;
+ ALenum newformat;
+ ALbuffer *albuf;
ALenum err;
- Context = GetContextRef();
- if(!Context) return;
-
- al_try
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(!(size >= 0 && freq > 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ switch(srctype)
{
- ALCdevice *device = Context->Device;
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- CHECK_VALUE(Context, size >= 0 && freq >= 0);
- if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE)
- al_throwerr(Context, AL_INVALID_ENUM);
- switch(SrcType)
- {
- case UserFmtByte:
- case UserFmtUByte:
- case UserFmtShort:
- case UserFmtUShort:
- case UserFmtFloat:
- FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
- CHECK_VALUE(Context, (size%FrameSize) == 0);
-
- err = LoadData(ALBuf, freq, format, size/FrameSize,
- SrcChannels, SrcType, data, AL_TRUE);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- break;
-
- case UserFmtInt:
- case UserFmtUInt:
- case UserFmtByte3:
- case UserFmtUByte3:
- case UserFmtDouble:
- FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
- CHECK_VALUE(Context, (size%FrameSize) == 0);
-
- NewFormat = AL_FORMAT_MONO_FLOAT32;
- switch(SrcChannels)
- {
- case UserFmtMono: NewFormat = AL_FORMAT_MONO_FLOAT32; break;
- case UserFmtStereo: NewFormat = AL_FORMAT_STEREO_FLOAT32; break;
- case UserFmtRear: NewFormat = AL_FORMAT_REAR32; break;
- case UserFmtQuad: NewFormat = AL_FORMAT_QUAD32; break;
- case UserFmtX51: NewFormat = AL_FORMAT_51CHN32; break;
- case UserFmtX61: NewFormat = AL_FORMAT_61CHN32; break;
- case UserFmtX71: NewFormat = AL_FORMAT_71CHN32; break;
- }
- err = LoadData(ALBuf, freq, NewFormat, size/FrameSize,
- SrcChannels, SrcType, data, AL_TRUE);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- break;
-
- case UserFmtMulaw:
- case UserFmtAlaw:
- FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
- CHECK_VALUE(Context, (size%FrameSize) == 0);
-
- NewFormat = AL_FORMAT_MONO16;
- switch(SrcChannels)
- {
- case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
- case UserFmtStereo: NewFormat = AL_FORMAT_STEREO16; break;
- case UserFmtRear: NewFormat = AL_FORMAT_REAR16; break;
- case UserFmtQuad: NewFormat = AL_FORMAT_QUAD16; break;
- case UserFmtX51: NewFormat = AL_FORMAT_51CHN16; break;
- case UserFmtX61: NewFormat = AL_FORMAT_61CHN16; break;
- case UserFmtX71: NewFormat = AL_FORMAT_71CHN16; break;
- }
- err = LoadData(ALBuf, freq, NewFormat, size/FrameSize,
- SrcChannels, SrcType, data, AL_TRUE);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- break;
-
- case UserFmtIMA4:
- /* Here is where things vary:
- * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
- * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
- */
- FrameSize = ChannelsFromUserFmt(SrcChannels) * 36;
- CHECK_VALUE(Context, (size%FrameSize) == 0);
-
- NewFormat = AL_FORMAT_MONO16;
- switch(SrcChannels)
- {
- case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
- case UserFmtStereo: NewFormat = AL_FORMAT_STEREO16; break;
- case UserFmtRear: NewFormat = AL_FORMAT_REAR16; break;
- case UserFmtQuad: NewFormat = AL_FORMAT_QUAD16; break;
- case UserFmtX51: NewFormat = AL_FORMAT_51CHN16; break;
- case UserFmtX61: NewFormat = AL_FORMAT_61CHN16; break;
- case UserFmtX71: NewFormat = AL_FORMAT_71CHN16; break;
- }
- err = LoadData(ALBuf, freq, NewFormat, size/FrameSize*65,
- SrcChannels, SrcType, data, AL_TRUE);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- break;
- }
+ case UserFmtByte:
+ case UserFmtUByte:
+ case UserFmtShort:
+ case UserFmtUShort:
+ case UserFmtFloat:
+ framesize = FrameSizeFromUserFmt(srcchannels, srctype);
+ if(!((size%framesize) == 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ err = LoadData(albuf, freq, format, size/framesize,
+ srcchannels, srctype, data, AL_TRUE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ break;
+
+ case UserFmtInt:
+ case UserFmtUInt:
+ case UserFmtByte3:
+ case UserFmtUByte3:
+ case UserFmtDouble:
+ framesize = FrameSizeFromUserFmt(srcchannels, srctype);
+ if(!((size%framesize) == 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ newformat = AL_FORMAT_MONO_FLOAT32;
+ switch(srcchannels)
+ {
+ case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
+ case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
+ case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
+ case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
+ case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
+ case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
+ case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
+ }
+ err = LoadData(albuf, freq, newformat, size/framesize,
+ srcchannels, srctype, data, AL_TRUE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ break;
+
+ case UserFmtMulaw:
+ case UserFmtAlaw:
+ framesize = FrameSizeFromUserFmt(srcchannels, srctype);
+ if(!((size%framesize) == 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ newformat = AL_FORMAT_MONO16;
+ switch(srcchannels)
+ {
+ case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
+ case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
+ case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
+ case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
+ case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
+ case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
+ case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ }
+ err = LoadData(albuf, freq, newformat, size/framesize,
+ srcchannels, srctype, data, AL_TRUE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ break;
+
+ case UserFmtIMA4:
+ /* Here is where things vary:
+ * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
+ * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
+ */
+ framesize = ChannelsFromUserFmt(srcchannels) * 36;
+ if(!((size%framesize) == 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ newformat = AL_FORMAT_MONO16;
+ switch(srcchannels)
+ {
+ case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
+ case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
+ case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
+ case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
+ case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
+ case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
+ case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ }
+ err = LoadData(albuf, freq, newformat, size/framesize*65,
+ srcchannels, srctype, data, AL_TRUE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
{
- enum UserFmtChannels SrcChannels;
- enum UserFmtType SrcType;
- ALCcontext *Context;
- ALbuffer *ALBuf;
-
- Context = GetContextRef();
- if(!Context) return;
-
- al_try
+ enum UserFmtChannels srcchannels;
+ enum UserFmtType srctype;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
+ ALuint original_align;
+ ALuint channels;
+ ALuint bytes;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(!(length >= 0 && offset >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+
+ WriteLock(&albuf->lock);
+ original_align = ((albuf->OriginalType == UserFmtIMA4) ?
+ (ChannelsFromUserFmt(albuf->OriginalChannels)*36) :
+ FrameSizeFromUserFmt(albuf->OriginalChannels,
+ albuf->OriginalType));
+
+ if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
{
- ALCdevice *device = Context->Device;
- ALuint original_align;
- ALuint Channels;
- ALuint Bytes;
-
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- CHECK_VALUE(Context, length >= 0 && offset >= 0);
- if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE)
- al_throwerr(Context, AL_INVALID_ENUM);
-
- WriteLock(&ALBuf->lock);
- original_align = ((ALBuf->OriginalType == UserFmtIMA4) ?
- (ChannelsFromUserFmt(ALBuf->OriginalChannels)*36) :
- FrameSizeFromUserFmt(ALBuf->OriginalChannels,
- ALBuf->OriginalType));
-
- if(SrcChannels != ALBuf->OriginalChannels || SrcType != ALBuf->OriginalType)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_ENUM);
- }
- if(offset > ALBuf->OriginalSize || length > ALBuf->OriginalSize-offset ||
- (offset%original_align) != 0 || (length%original_align) != 0)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_VALUE);
- }
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+ if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
+ (offset%original_align) != 0 || (length%original_align) != 0)
+ {
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
- Channels = ChannelsFromFmt(ALBuf->FmtChannels);
- Bytes = BytesFromFmt(ALBuf->FmtType);
- /* offset -> byte offset, length -> sample count */
- if(SrcType == UserFmtIMA4)
- {
- offset = offset/36*65 * Bytes;
- length = length/original_align * 65;
- }
- else
- {
- ALuint OldBytes = BytesFromUserFmt(SrcType);
- offset = offset/OldBytes * Bytes;
- length = length/OldBytes/Channels;
- }
- ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
- data, SrcType, Channels, length);
- WriteUnlock(&ALBuf->lock);
+ channels = ChannelsFromFmt(albuf->FmtChannels);
+ bytes = BytesFromFmt(albuf->FmtType);
+ /* offset -> byte offset, length -> sample count */
+ if(srctype == UserFmtIMA4)
+ {
+ offset = offset/36*65 * bytes;
+ length = length/original_align * 65;
+ }
+ else
+ {
+ ALuint OldBytes = BytesFromUserFmt(srctype);
+ offset = offset/OldBytes * bytes;
+ length = length/OldBytes/channels;
}
- al_endtry;
+ ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
+ data, srctype, channels, length);
+ WriteUnlock(&albuf->lock);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
@@ -470,394 +473,366 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
ALuint samplerate, ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type, const ALvoid *data)
{
- ALCcontext *Context;
- ALbuffer *ALBuf;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- CHECK_VALUE(Context, samples >= 0 && samplerate != 0);
- if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
- al_throwerr(Context, AL_INVALID_ENUM);
-
- err = LoadData(ALBuf, samplerate, internalformat, samples,
- channels, type, data, AL_FALSE);
- if(err != AL_NO_ERROR)
- al_throwerr(Context, err);
- }
- al_endtry;
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(!(samples >= 0 && samplerate != 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+
+ err = LoadData(albuf, samplerate, internalformat, samples,
+ channels, type, data, AL_FALSE);
+ if(err != AL_NO_ERROR)
+ SET_ERROR_AND_GOTO(context, err, done);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
ALsizei offset, ALsizei samples,
ALenum channels, ALenum type, const ALvoid *data)
{
- ALCcontext *Context;
- ALbuffer *ALBuf;
-
- Context = GetContextRef();
- if(!Context) return;
-
- al_try
+ ALCdevice *device;
+ ALCcontext *context;
+ ALuint framesize;
+ ALbuffer *albuf;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(!(samples >= 0 && offset >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(IsValidType(type) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+
+ WriteLock(&albuf->lock);
+ framesize = FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
+ if(channels != (ALenum)albuf->FmtChannels)
{
- ALCdevice *device = Context->Device;
- ALuint FrameSize;
-
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- CHECK_VALUE(Context, samples >= 0 && offset >= 0);
- if(IsValidType(type) == AL_FALSE)
- al_throwerr(Context, AL_INVALID_ENUM);
-
- WriteLock(&ALBuf->lock);
- FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
- if(channels != (ALenum)ALBuf->FmtChannels)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_ENUM);
- }
- else if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context,AL_INVALID_VALUE);
- }
-
- /* offset -> byte offset */
- offset *= FrameSize;
- ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
- data, type, ChannelsFromFmt(ALBuf->FmtChannels), samples);
- WriteUnlock(&ALBuf->lock);
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
+ else if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
+ {
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
+
+ /* offset -> byte offset */
+ offset *= framesize;
+ ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
+ data, type, ChannelsFromFmt(albuf->FmtChannels), samples);
+ WriteUnlock(&albuf->lock);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
ALsizei offset, ALsizei samples,
ALenum channels, ALenum type, ALvoid *data)
{
- ALCcontext *Context;
- ALbuffer *ALBuf;
-
- Context = GetContextRef();
- if(!Context) return;
-
- al_try
+ ALCdevice *device;
+ ALCcontext *context;
+ ALuint framesize;
+ ALbuffer *albuf;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(!(samples >= 0 && offset >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(IsValidType(type) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+
+ ReadLock(&albuf->lock);
+ framesize = FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
+ if(channels != (ALenum)albuf->FmtChannels)
{
- ALCdevice *device = Context->Device;
- ALuint FrameSize;
-
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- CHECK_VALUE(Context, samples >= 0 && offset >= 0);
- if(IsValidType(type) == AL_FALSE)
- al_throwerr(Context, AL_INVALID_ENUM);
-
- ReadLock(&ALBuf->lock);
- FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
- if(channels != (ALenum)ALBuf->FmtChannels)
- {
- ReadUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_ENUM);
- }
- if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset)
- {
- ReadUnlock(&ALBuf->lock);
- al_throwerr(Context,AL_INVALID_VALUE);
- }
- if(type == UserFmtIMA4 && (samples%65) != 0)
- {
- ReadUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_VALUE);
- }
-
- /* offset -> byte offset */
- offset *= FrameSize;
- ConvertData(data, type, &((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
- ChannelsFromFmt(ALBuf->FmtChannels), samples);
- ReadUnlock(&ALBuf->lock);
+ ReadUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+ if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
+ {
+ ReadUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
+ if(type == UserFmtIMA4 && (samples%65) != 0)
+ {
+ ReadUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+ /* offset -> byte offset */
+ offset *= framesize;
+ ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
+ ChannelsFromFmt(albuf->FmtChannels), samples);
+ ReadUnlock(&albuf->lock);
+
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
{
- enum FmtChannels DstChannels;
- enum FmtType DstType;
- ALCcontext *Context;
+ enum FmtChannels dstchannels;
+ enum FmtType dsttype;
+ ALCcontext *context;
ALboolean ret;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- ret = DecomposeFormat(format, &DstChannels, &DstType);
+ ret = DecomposeFormat(format, &dstchannels, &dsttype);
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
return ret;
}
-AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value)
+AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- (void)value;
+ context = GetContextRef();
+ if(!context) return;
- Context = GetContextRef();
- if(!Context) return;
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- al_try
+ switch(param)
{
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
-
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
-AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
+AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- (void)value1;
- (void)value2;
- (void)value3;
+ context = GetContextRef();
+ if(!context) return;
- Context = GetContextRef();
- if(!Context) return;
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- al_try
+ switch(param)
{
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
-
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, values);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
-AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
+AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint UNUSED(value))
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- (void)value;
+ context = GetContextRef();
+ if(!context) return;
- Context = GetContextRef();
- if(!Context) return;
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- al_try
+ switch(param)
{
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
-
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
-AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3)
+AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- (void)value1;
- (void)value2;
- (void)value3;
+ context = GetContextRef();
+ if(!context) return;
- Context = GetContextRef();
- if(!Context) return;
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- al_try
+ switch(param)
{
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
-
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
{
- ALCcontext *Context;
- ALbuffer *ALBuf;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, values);
- switch(param)
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ case AL_LOOP_POINTS_SOFT:
+ WriteLock(&albuf->lock);
+ if(albuf->ref != 0)
{
- case AL_LOOP_POINTS_SOFT:
- WriteLock(&ALBuf->lock);
- if(ALBuf->ref != 0)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_OPERATION);
- }
- if(values[0] >= values[1] || values[0] < 0 ||
- values[1] > ALBuf->SampleLen)
- {
- WriteUnlock(&ALBuf->lock);
- al_throwerr(Context, AL_INVALID_VALUE);
- }
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+ if(values[0] >= values[1] || values[0] < 0 ||
+ values[1] > albuf->SampleLen)
+ {
+ WriteUnlock(&albuf->lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
- ALBuf->LoopStart = values[0];
- ALBuf->LoopEnd = values[1];
- WriteUnlock(&ALBuf->lock);
- break;
+ albuf->LoopStart = values[0];
+ albuf->LoopEnd = values[1];
+ WriteUnlock(&albuf->lock);
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
{
- ALCcontext *Context;
- ALbuffer *Buffer;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if((Buffer=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, value);
- switch(param)
- {
- case AL_SEC_LENGTH_SOFT:
- ReadLock(&Buffer->lock);
- if(Buffer->SampleLen != 0)
- *value = Buffer->SampleLen / (ALfloat)Buffer->Frequency;
- else
- *value = 0.0f;
- ReadUnlock(&Buffer->lock);
- break;
+ if(!(value))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ case AL_SEC_LENGTH_SOFT:
+ ReadLock(&albuf->lock);
+ if(albuf->SampleLen != 0)
+ *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
+ else
+ *value = 0.0f;
+ ReadUnlock(&albuf->lock);
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, value1 && value2 && value3);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ if(!(value1 && value2 && value3))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
switch(param)
{
@@ -866,116 +841,113 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu
return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, values);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
{
- ALCcontext *Context;
- ALbuffer *Buffer;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if((Buffer=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, value);
- switch(param)
- {
- case AL_FREQUENCY:
- *value = Buffer->Frequency;
- break;
+ if(!(value))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ case AL_FREQUENCY:
+ *value = albuf->Frequency;
+ break;
- case AL_BITS:
- *value = BytesFromFmt(Buffer->FmtType) * 8;
- break;
+ case AL_BITS:
+ *value = BytesFromFmt(albuf->FmtType) * 8;
+ break;
- case AL_CHANNELS:
- *value = ChannelsFromFmt(Buffer->FmtChannels);
- break;
+ case AL_CHANNELS:
+ *value = ChannelsFromFmt(albuf->FmtChannels);
+ break;
- case AL_SIZE:
- ReadLock(&Buffer->lock);
- *value = Buffer->SampleLen * FrameSizeFromFmt(Buffer->FmtChannels,
- Buffer->FmtType);
- ReadUnlock(&Buffer->lock);
- break;
+ case AL_SIZE:
+ ReadLock(&albuf->lock);
+ *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
+ albuf->FmtType);
+ ReadUnlock(&albuf->lock);
+ break;
- case AL_INTERNAL_FORMAT_SOFT:
- *value = Buffer->Format;
- break;
+ case AL_INTERNAL_FORMAT_SOFT:
+ *value = albuf->Format;
+ break;
- case AL_BYTE_LENGTH_SOFT:
- *value = Buffer->OriginalSize;
- break;
+ case AL_BYTE_LENGTH_SOFT:
+ *value = albuf->OriginalSize;
+ break;
- case AL_SAMPLE_LENGTH_SOFT:
- *value = Buffer->SampleLen;
- break;
+ case AL_SAMPLE_LENGTH_SOFT:
+ *value = albuf->SampleLen;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if(LookupBuffer(device, buffer) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ device = context->Device;
+ if(LookupBuffer(device, buffer) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- CHECK_VALUE(Context, value1 && value2 && value3);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ if(!(value1 && value2 && value3))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
{
- ALCcontext *Context;
- ALbuffer *ALBuf;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALbuffer *albuf;
switch(param)
{
@@ -990,32 +962,30 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values
return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- if((ALBuf=LookupBuffer(device, buffer)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
-
- CHECK_VALUE(Context, values);
- switch(param)
- {
- case AL_LOOP_POINTS_SOFT:
- ReadLock(&ALBuf->lock);
- values[0] = ALBuf->LoopStart;
- values[1] = ALBuf->LoopEnd;
- ReadUnlock(&ALBuf->lock);
- break;
+ device = context->Device;
+ if((albuf=LookupBuffer(device, buffer)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
+ {
+ case AL_LOOP_POINTS_SOFT:
+ ReadLock(&albuf->lock);
+ values[0] = albuf->LoopStart;
+ values[1] = albuf->LoopEnd;
+ ReadUnlock(&albuf->lock);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
@@ -1031,7 +1001,7 @@ typedef struct {
} ALubyte3;
extern ALbyte ALubyte3_size_is_not_3[(sizeof(ALubyte3)==sizeof(ALubyte[3]))?1:-1];
-static __inline ALshort DecodeMuLaw(ALmulaw val)
+static inline ALshort DecodeMuLaw(ALmulaw val)
{ return muLawDecompressionTable[val]; }
static ALmulaw EncodeMuLaw(ALshort val)
@@ -1056,7 +1026,7 @@ static ALmulaw EncodeMuLaw(ALshort val)
return ~(sign | (exp<<4) | mant);
}
-static __inline ALshort DecodeALaw(ALalaw val)
+static inline ALshort DecodeALaw(ALalaw val)
{ return aLawDecompressionTable[val]; }
static ALalaw EncodeALaw(ALshort val)
@@ -1087,8 +1057,8 @@ static ALalaw EncodeALaw(ALshort val)
static void DecodeIMA4Block(ALshort *dst, const ALima4 *src, ALint numchans)
{
- ALint sample[MaxChannels], index[MaxChannels];
- ALuint code[MaxChannels];
+ ALint sample[MAX_INPUT_CHANNELS], index[MAX_INPUT_CHANNELS];
+ ALuint code[MAX_INPUT_CHANNELS];
ALsizei j,k,c;
for(c = 0;c < numchans;c++)
@@ -1203,14 +1173,14 @@ static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALin
}
-static __inline ALint DecodeByte3(ALbyte3 val)
+static inline ALint DecodeByte3(ALbyte3 val)
{
if(IS_LITTLE_ENDIAN)
return (val.b[2]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[0]);
return (val.b[0]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[2]);
}
-static __inline ALbyte3 EncodeByte3(ALint val)
+static inline ALbyte3 EncodeByte3(ALint val)
{
if(IS_LITTLE_ENDIAN)
{
@@ -1224,14 +1194,14 @@ static __inline ALbyte3 EncodeByte3(ALint val)
}
}
-static __inline ALint DecodeUByte3(ALubyte3 val)
+static inline ALint DecodeUByte3(ALubyte3 val)
{
if(IS_LITTLE_ENDIAN)
return (val.b[2]<<16) | (val.b[1]<<8) | (val.b[0]);
return (val.b[0]<<16) | (val.b[1]<<8) | val.b[2];
}
-static __inline ALubyte3 EncodeUByte3(ALint val)
+static inline ALubyte3 EncodeUByte3(ALint val)
{
if(IS_LITTLE_ENDIAN)
{
@@ -1246,256 +1216,256 @@ static __inline ALubyte3 EncodeUByte3(ALint val)
}
-static __inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
+static inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
{ return val; }
-static __inline ALbyte Conv_ALbyte_ALubyte(ALubyte val)
+static inline ALbyte Conv_ALbyte_ALubyte(ALubyte val)
{ return val-128; }
-static __inline ALbyte Conv_ALbyte_ALshort(ALshort val)
+static inline ALbyte Conv_ALbyte_ALshort(ALshort val)
{ return val>>8; }
-static __inline ALbyte Conv_ALbyte_ALushort(ALushort val)
+static inline ALbyte Conv_ALbyte_ALushort(ALushort val)
{ return (val>>8)-128; }
-static __inline ALbyte Conv_ALbyte_ALint(ALint val)
+static inline ALbyte Conv_ALbyte_ALint(ALint val)
{ return val>>24; }
-static __inline ALbyte Conv_ALbyte_ALuint(ALuint val)
+static inline ALbyte Conv_ALbyte_ALuint(ALuint val)
{ return (val>>24)-128; }
-static __inline ALbyte Conv_ALbyte_ALfloat(ALfloat val)
+static inline ALbyte Conv_ALbyte_ALfloat(ALfloat val)
{
if(val > 1.0f) return 127;
if(val < -1.0f) return -128;
return (ALint)(val * 127.0f);
}
-static __inline ALbyte Conv_ALbyte_ALdouble(ALdouble val)
+static inline ALbyte Conv_ALbyte_ALdouble(ALdouble val)
{
if(val > 1.0) return 127;
if(val < -1.0) return -128;
return (ALint)(val * 127.0);
}
-static __inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val)
+static inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val)
{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); }
-static __inline ALbyte Conv_ALbyte_ALalaw(ALalaw val)
+static inline ALbyte Conv_ALbyte_ALalaw(ALalaw val)
{ return Conv_ALbyte_ALshort(DecodeALaw(val)); }
-static __inline ALbyte Conv_ALbyte_ALbyte3(ALbyte3 val)
+static inline ALbyte Conv_ALbyte_ALbyte3(ALbyte3 val)
{ return DecodeByte3(val)>>16; }
-static __inline ALbyte Conv_ALbyte_ALubyte3(ALubyte3 val)
+static inline ALbyte Conv_ALbyte_ALubyte3(ALubyte3 val)
{ return (DecodeUByte3(val)>>16)-128; }
-static __inline ALubyte Conv_ALubyte_ALbyte(ALbyte val)
+static inline ALubyte Conv_ALubyte_ALbyte(ALbyte val)
{ return val+128; }
-static __inline ALubyte Conv_ALubyte_ALubyte(ALubyte val)
+static inline ALubyte Conv_ALubyte_ALubyte(ALubyte val)
{ return val; }
-static __inline ALubyte Conv_ALubyte_ALshort(ALshort val)
+static inline ALubyte Conv_ALubyte_ALshort(ALshort val)
{ return (val>>8)+128; }
-static __inline ALubyte Conv_ALubyte_ALushort(ALushort val)
+static inline ALubyte Conv_ALubyte_ALushort(ALushort val)
{ return val>>8; }
-static __inline ALubyte Conv_ALubyte_ALint(ALint val)
+static inline ALubyte Conv_ALubyte_ALint(ALint val)
{ return (val>>24)+128; }
-static __inline ALubyte Conv_ALubyte_ALuint(ALuint val)
+static inline ALubyte Conv_ALubyte_ALuint(ALuint val)
{ return val>>24; }
-static __inline ALubyte Conv_ALubyte_ALfloat(ALfloat val)
+static inline ALubyte Conv_ALubyte_ALfloat(ALfloat val)
{
if(val > 1.0f) return 255;
if(val < -1.0f) return 0;
return (ALint)(val * 127.0f) + 128;
}
-static __inline ALubyte Conv_ALubyte_ALdouble(ALdouble val)
+static inline ALubyte Conv_ALubyte_ALdouble(ALdouble val)
{
if(val > 1.0) return 255;
if(val < -1.0) return 0;
return (ALint)(val * 127.0) + 128;
}
-static __inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val)
+static inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val)
{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); }
-static __inline ALubyte Conv_ALubyte_ALalaw(ALalaw val)
+static inline ALubyte Conv_ALubyte_ALalaw(ALalaw val)
{ return Conv_ALubyte_ALshort(DecodeALaw(val)); }
-static __inline ALubyte Conv_ALubyte_ALbyte3(ALbyte3 val)
+static inline ALubyte Conv_ALubyte_ALbyte3(ALbyte3 val)
{ return (DecodeByte3(val)>>16)+128; }
-static __inline ALubyte Conv_ALubyte_ALubyte3(ALubyte3 val)
+static inline ALubyte Conv_ALubyte_ALubyte3(ALubyte3 val)
{ return DecodeUByte3(val)>>16; }
-static __inline ALshort Conv_ALshort_ALbyte(ALbyte val)
+static inline ALshort Conv_ALshort_ALbyte(ALbyte val)
{ return val<<8; }
-static __inline ALshort Conv_ALshort_ALubyte(ALubyte val)
+static inline ALshort Conv_ALshort_ALubyte(ALubyte val)
{ return (val-128)<<8; }
-static __inline ALshort Conv_ALshort_ALshort(ALshort val)
+static inline ALshort Conv_ALshort_ALshort(ALshort val)
{ return val; }
-static __inline ALshort Conv_ALshort_ALushort(ALushort val)
+static inline ALshort Conv_ALshort_ALushort(ALushort val)
{ return val-32768; }
-static __inline ALshort Conv_ALshort_ALint(ALint val)
+static inline ALshort Conv_ALshort_ALint(ALint val)
{ return val>>16; }
-static __inline ALshort Conv_ALshort_ALuint(ALuint val)
+static inline ALshort Conv_ALshort_ALuint(ALuint val)
{ return (val>>16)-32768; }
-static __inline ALshort Conv_ALshort_ALfloat(ALfloat val)
+static inline ALshort Conv_ALshort_ALfloat(ALfloat val)
{
if(val > 1.0f) return 32767;
if(val < -1.0f) return -32768;
return (ALint)(val * 32767.0f);
}
-static __inline ALshort Conv_ALshort_ALdouble(ALdouble val)
+static inline ALshort Conv_ALshort_ALdouble(ALdouble val)
{
if(val > 1.0) return 32767;
if(val < -1.0) return -32768;
return (ALint)(val * 32767.0);
}
-static __inline ALshort Conv_ALshort_ALmulaw(ALmulaw val)
+static inline ALshort Conv_ALshort_ALmulaw(ALmulaw val)
{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); }
-static __inline ALshort Conv_ALshort_ALalaw(ALalaw val)
+static inline ALshort Conv_ALshort_ALalaw(ALalaw val)
{ return Conv_ALshort_ALshort(DecodeALaw(val)); }
-static __inline ALshort Conv_ALshort_ALbyte3(ALbyte3 val)
+static inline ALshort Conv_ALshort_ALbyte3(ALbyte3 val)
{ return DecodeByte3(val)>>8; }
-static __inline ALshort Conv_ALshort_ALubyte3(ALubyte3 val)
+static inline ALshort Conv_ALshort_ALubyte3(ALubyte3 val)
{ return (DecodeUByte3(val)>>8)-32768; }
-static __inline ALushort Conv_ALushort_ALbyte(ALbyte val)
+static inline ALushort Conv_ALushort_ALbyte(ALbyte val)
{ return (val+128)<<8; }
-static __inline ALushort Conv_ALushort_ALubyte(ALubyte val)
+static inline ALushort Conv_ALushort_ALubyte(ALubyte val)
{ return val<<8; }
-static __inline ALushort Conv_ALushort_ALshort(ALshort val)
+static inline ALushort Conv_ALushort_ALshort(ALshort val)
{ return val+32768; }
-static __inline ALushort Conv_ALushort_ALushort(ALushort val)
+static inline ALushort Conv_ALushort_ALushort(ALushort val)
{ return val; }
-static __inline ALushort Conv_ALushort_ALint(ALint val)
+static inline ALushort Conv_ALushort_ALint(ALint val)
{ return (val>>16)+32768; }
-static __inline ALushort Conv_ALushort_ALuint(ALuint val)
+static inline ALushort Conv_ALushort_ALuint(ALuint val)
{ return val>>16; }
-static __inline ALushort Conv_ALushort_ALfloat(ALfloat val)
+static inline ALushort Conv_ALushort_ALfloat(ALfloat val)
{
if(val > 1.0f) return 65535;
if(val < -1.0f) return 0;
return (ALint)(val * 32767.0f) + 32768;
}
-static __inline ALushort Conv_ALushort_ALdouble(ALdouble val)
+static inline ALushort Conv_ALushort_ALdouble(ALdouble val)
{
if(val > 1.0) return 65535;
if(val < -1.0) return 0;
return (ALint)(val * 32767.0) + 32768;
}
-static __inline ALushort Conv_ALushort_ALmulaw(ALmulaw val)
+static inline ALushort Conv_ALushort_ALmulaw(ALmulaw val)
{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); }
-static __inline ALushort Conv_ALushort_ALalaw(ALalaw val)
+static inline ALushort Conv_ALushort_ALalaw(ALalaw val)
{ return Conv_ALushort_ALshort(DecodeALaw(val)); }
-static __inline ALushort Conv_ALushort_ALbyte3(ALbyte3 val)
+static inline ALushort Conv_ALushort_ALbyte3(ALbyte3 val)
{ return (DecodeByte3(val)>>8)+32768; }
-static __inline ALushort Conv_ALushort_ALubyte3(ALubyte3 val)
+static inline ALushort Conv_ALushort_ALubyte3(ALubyte3 val)
{ return DecodeUByte3(val)>>8; }
-static __inline ALint Conv_ALint_ALbyte(ALbyte val)
+static inline ALint Conv_ALint_ALbyte(ALbyte val)
{ return val<<24; }
-static __inline ALint Conv_ALint_ALubyte(ALubyte val)
+static inline ALint Conv_ALint_ALubyte(ALubyte val)
{ return (val-128)<<24; }
-static __inline ALint Conv_ALint_ALshort(ALshort val)
+static inline ALint Conv_ALint_ALshort(ALshort val)
{ return val<<16; }
-static __inline ALint Conv_ALint_ALushort(ALushort val)
+static inline ALint Conv_ALint_ALushort(ALushort val)
{ return (val-32768)<<16; }
-static __inline ALint Conv_ALint_ALint(ALint val)
+static inline ALint Conv_ALint_ALint(ALint val)
{ return val; }
-static __inline ALint Conv_ALint_ALuint(ALuint val)
+static inline ALint Conv_ALint_ALuint(ALuint val)
{ return val-2147483648u; }
-static __inline ALint Conv_ALint_ALfloat(ALfloat val)
+static inline ALint Conv_ALint_ALfloat(ALfloat val)
{
if(val > 1.0f) return 2147483647;
if(val < -1.0f) return -2147483647-1;
- return (ALint)(val * 2147483647.0);
+ return (ALint)(val*16777215.0f) << 7;
}
-static __inline ALint Conv_ALint_ALdouble(ALdouble val)
+static inline ALint Conv_ALint_ALdouble(ALdouble val)
{
if(val > 1.0) return 2147483647;
if(val < -1.0) return -2147483647-1;
return (ALint)(val * 2147483647.0);
}
-static __inline ALint Conv_ALint_ALmulaw(ALmulaw val)
+static inline ALint Conv_ALint_ALmulaw(ALmulaw val)
{ return Conv_ALint_ALshort(DecodeMuLaw(val)); }
-static __inline ALint Conv_ALint_ALalaw(ALalaw val)
+static inline ALint Conv_ALint_ALalaw(ALalaw val)
{ return Conv_ALint_ALshort(DecodeALaw(val)); }
-static __inline ALint Conv_ALint_ALbyte3(ALbyte3 val)
+static inline ALint Conv_ALint_ALbyte3(ALbyte3 val)
{ return DecodeByte3(val)<<8; }
-static __inline ALint Conv_ALint_ALubyte3(ALubyte3 val)
+static inline ALint Conv_ALint_ALubyte3(ALubyte3 val)
{ return (DecodeUByte3(val)-8388608)<<8; }
-static __inline ALuint Conv_ALuint_ALbyte(ALbyte val)
+static inline ALuint Conv_ALuint_ALbyte(ALbyte val)
{ return (val+128)<<24; }
-static __inline ALuint Conv_ALuint_ALubyte(ALubyte val)
+static inline ALuint Conv_ALuint_ALubyte(ALubyte val)
{ return val<<24; }
-static __inline ALuint Conv_ALuint_ALshort(ALshort val)
+static inline ALuint Conv_ALuint_ALshort(ALshort val)
{ return (val+32768)<<16; }
-static __inline ALuint Conv_ALuint_ALushort(ALushort val)
+static inline ALuint Conv_ALuint_ALushort(ALushort val)
{ return val<<16; }
-static __inline ALuint Conv_ALuint_ALint(ALint val)
+static inline ALuint Conv_ALuint_ALint(ALint val)
{ return val+2147483648u; }
-static __inline ALuint Conv_ALuint_ALuint(ALuint val)
+static inline ALuint Conv_ALuint_ALuint(ALuint val)
{ return val; }
-static __inline ALuint Conv_ALuint_ALfloat(ALfloat val)
+static inline ALuint Conv_ALuint_ALfloat(ALfloat val)
{
if(val > 1.0f) return 4294967295u;
if(val < -1.0f) return 0;
- return (ALint)(val * 2147483647.0) + 2147483648u;
+ return ((ALint)(val*16777215.0f)<<7) + 2147483648u;
}
-static __inline ALuint Conv_ALuint_ALdouble(ALdouble val)
+static inline ALuint Conv_ALuint_ALdouble(ALdouble val)
{
if(val > 1.0) return 4294967295u;
if(val < -1.0) return 0;
return (ALint)(val * 2147483647.0) + 2147483648u;
}
-static __inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
+static inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); }
-static __inline ALuint Conv_ALuint_ALalaw(ALalaw val)
+static inline ALuint Conv_ALuint_ALalaw(ALalaw val)
{ return Conv_ALuint_ALshort(DecodeALaw(val)); }
-static __inline ALuint Conv_ALuint_ALbyte3(ALbyte3 val)
+static inline ALuint Conv_ALuint_ALbyte3(ALbyte3 val)
{ return (DecodeByte3(val)+8388608)<<8; }
-static __inline ALuint Conv_ALuint_ALubyte3(ALubyte3 val)
+static inline ALuint Conv_ALuint_ALubyte3(ALubyte3 val)
{ return DecodeUByte3(val)<<8; }
-static __inline ALfloat Conv_ALfloat_ALbyte(ALbyte val)
+static inline ALfloat Conv_ALfloat_ALbyte(ALbyte val)
{ return val * (1.0f/127.0f); }
-static __inline ALfloat Conv_ALfloat_ALubyte(ALubyte val)
+static inline ALfloat Conv_ALfloat_ALubyte(ALubyte val)
{ return (val-128) * (1.0f/127.0f); }
-static __inline ALfloat Conv_ALfloat_ALshort(ALshort val)
+static inline ALfloat Conv_ALfloat_ALshort(ALshort val)
{ return val * (1.0f/32767.0f); }
-static __inline ALfloat Conv_ALfloat_ALushort(ALushort val)
+static inline ALfloat Conv_ALfloat_ALushort(ALushort val)
{ return (val-32768) * (1.0f/32767.0f); }
-static __inline ALfloat Conv_ALfloat_ALint(ALint val)
+static inline ALfloat Conv_ALfloat_ALint(ALint val)
{ return (ALfloat)(val * (1.0/2147483647.0)); }
-static __inline ALfloat Conv_ALfloat_ALuint(ALuint val)
+static inline ALfloat Conv_ALfloat_ALuint(ALuint val)
{ return (ALfloat)((ALint)(val-2147483648u) * (1.0/2147483647.0)); }
-static __inline ALfloat Conv_ALfloat_ALfloat(ALfloat val)
+static inline ALfloat Conv_ALfloat_ALfloat(ALfloat val)
{ return (val==val) ? val : 0.0f; }
-static __inline ALfloat Conv_ALfloat_ALdouble(ALdouble val)
+static inline ALfloat Conv_ALfloat_ALdouble(ALdouble val)
{ return (val==val) ? (ALfloat)val : 0.0f; }
-static __inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val)
+static inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val)
{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); }
-static __inline ALfloat Conv_ALfloat_ALalaw(ALalaw val)
+static inline ALfloat Conv_ALfloat_ALalaw(ALalaw val)
{ return Conv_ALfloat_ALshort(DecodeALaw(val)); }
-static __inline ALfloat Conv_ALfloat_ALbyte3(ALbyte3 val)
+static inline ALfloat Conv_ALfloat_ALbyte3(ALbyte3 val)
{ return (ALfloat)(DecodeByte3(val) * (1.0/8388607.0)); }
-static __inline ALfloat Conv_ALfloat_ALubyte3(ALubyte3 val)
+static inline ALfloat Conv_ALfloat_ALubyte3(ALubyte3 val)
{ return (ALfloat)((DecodeUByte3(val)-8388608) * (1.0/8388607.0)); }
-static __inline ALdouble Conv_ALdouble_ALbyte(ALbyte val)
+static inline ALdouble Conv_ALdouble_ALbyte(ALbyte val)
{ return val * (1.0/127.0); }
-static __inline ALdouble Conv_ALdouble_ALubyte(ALubyte val)
+static inline ALdouble Conv_ALdouble_ALubyte(ALubyte val)
{ return (val-128) * (1.0/127.0); }
-static __inline ALdouble Conv_ALdouble_ALshort(ALshort val)
+static inline ALdouble Conv_ALdouble_ALshort(ALshort val)
{ return val * (1.0/32767.0); }
-static __inline ALdouble Conv_ALdouble_ALushort(ALushort val)
+static inline ALdouble Conv_ALdouble_ALushort(ALushort val)
{ return (val-32768) * (1.0/32767.0); }
-static __inline ALdouble Conv_ALdouble_ALint(ALint val)
+static inline ALdouble Conv_ALdouble_ALint(ALint val)
{ return val * (1.0/2147483647.0); }
-static __inline ALdouble Conv_ALdouble_ALuint(ALuint val)
+static inline ALdouble Conv_ALdouble_ALuint(ALuint val)
{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
-static __inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
+static inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
{ return (val==val) ? val : 0.0f; }
-static __inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
+static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
{ return (val==val) ? val : 0.0; }
-static __inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val)
+static inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val)
{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); }
-static __inline ALdouble Conv_ALdouble_ALalaw(ALalaw val)
+static inline ALdouble Conv_ALdouble_ALalaw(ALalaw val)
{ return Conv_ALdouble_ALshort(DecodeALaw(val)); }
-static __inline ALdouble Conv_ALdouble_ALbyte3(ALbyte3 val)
+static inline ALdouble Conv_ALdouble_ALbyte3(ALbyte3 val)
{ return DecodeByte3(val) * (1.0/8388607.0); }
-static __inline ALdouble Conv_ALdouble_ALubyte3(ALubyte3 val)
+static inline ALdouble Conv_ALdouble_ALubyte3(ALubyte3 val)
{ return (DecodeUByte3(val)-8388608) * (1.0/8388607.0); }
#define DECL_TEMPLATE(T) \
-static __inline ALmulaw Conv_ALmulaw_##T(T val) \
+static inline ALmulaw Conv_ALmulaw_##T(T val) \
{ return EncodeMuLaw(Conv_ALshort_##T(val)); }
DECL_TEMPLATE(ALbyte)
@@ -1506,7 +1476,7 @@ DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALdouble)
-static __inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val)
+static inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val)
{ return val; }
DECL_TEMPLATE(ALalaw)
DECL_TEMPLATE(ALbyte3)
@@ -1515,7 +1485,7 @@ DECL_TEMPLATE(ALubyte3)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
-static __inline ALalaw Conv_ALalaw_##T(T val) \
+static inline ALalaw Conv_ALalaw_##T(T val) \
{ return EncodeALaw(Conv_ALshort_##T(val)); }
DECL_TEMPLATE(ALbyte)
@@ -1527,7 +1497,7 @@ DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
-static __inline ALalaw Conv_ALalaw_ALalaw(ALalaw val)
+static inline ALalaw Conv_ALalaw_ALalaw(ALalaw val)
{ return val; }
DECL_TEMPLATE(ALbyte3)
DECL_TEMPLATE(ALubyte3)
@@ -1535,7 +1505,7 @@ DECL_TEMPLATE(ALubyte3)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
-static __inline ALbyte3 Conv_ALbyte3_##T(T val) \
+static inline ALbyte3 Conv_ALbyte3_##T(T val) \
{ return EncodeByte3(Conv_ALint_##T(val)>>8); }
DECL_TEMPLATE(ALbyte)
@@ -1548,14 +1518,14 @@ DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
DECL_TEMPLATE(ALalaw)
-static __inline ALbyte3 Conv_ALbyte3_ALbyte3(ALbyte3 val)
+static inline ALbyte3 Conv_ALbyte3_ALbyte3(ALbyte3 val)
{ return val; }
DECL_TEMPLATE(ALubyte3)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
-static __inline ALubyte3 Conv_ALubyte3_##T(T val) \
+static inline ALubyte3 Conv_ALubyte3_##T(T val) \
{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); }
DECL_TEMPLATE(ALbyte)
@@ -1569,7 +1539,7 @@ DECL_TEMPLATE(ALdouble)
DECL_TEMPLATE(ALmulaw)
DECL_TEMPLATE(ALalaw)
DECL_TEMPLATE(ALbyte3)
-static __inline ALubyte3 Conv_ALubyte3_ALubyte3(ALubyte3 val)
+static inline ALubyte3 Conv_ALubyte3_ALubyte3(ALubyte3 val)
{ return val; }
#undef DECL_TEMPLATE
@@ -1749,7 +1719,7 @@ DECL_TEMPLATE(ALubyte3, ALubyte3)
static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \
ALuint len) \
{ \
- ALshort tmp[65*MaxChannels]; /* Max samples an IMA4 frame can be */ \
+ ALshort tmp[65*MAX_INPUT_CHANNELS]; /* Max samples an IMA4 frame can be */\
ALuint i, j, k; \
\
i = 0; \
@@ -1785,7 +1755,7 @@ DECL_TEMPLATE(ALubyte3)
static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \
ALuint len) \
{ \
- ALshort tmp[65*MaxChannels]; /* Max samples an IMA4 frame can be */ \
+ ALshort tmp[65*MAX_INPUT_CHANNELS]; /* Max samples an IMA4 frame can be */\
ALint sample[MaxChannels] = {0,0,0,0,0,0,0,0}; \
ALint index[MaxChannels] = {0,0,0,0,0,0,0,0}; \
ALuint i, j; \
@@ -1973,7 +1943,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
ALBuf->data = temp;
if(data != NULL)
- ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
+ ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames);
if(storesrc)
{
@@ -1986,8 +1956,8 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
}
else
{
- ALBuf->OriginalChannels = DstChannels;
- ALBuf->OriginalType = DstType;
+ ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
+ ALBuf->OriginalType = (enum UserFmtType)DstType;
ALBuf->OriginalSize = frames * NewBytes * NewChannels;
}
diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c
index 4d257641..c9e5928f 100644
--- a/OpenAL32/alEffect.c
+++ b/OpenAL32/alEffect.c
@@ -34,91 +34,88 @@
ALboolean DisabledEffects[MAX_EFFECTS];
+extern inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id);
+extern inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id);
+extern inline ALboolean IsReverbEffect(ALenum type);
static void InitEffectParams(ALeffect *effect, ALenum type);
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
- ALCcontext *Context;
- ALsizei cur = 0;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsizei cur;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- ALenum err;
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- CHECK_VALUE(Context, n >= 0);
- for(cur = 0;cur < n;cur++)
+ device = context->Device;
+ for(cur = 0;cur < n;cur++)
+ {
+ ALeffect *effect = calloc(1, sizeof(ALeffect));
+ ALenum err = AL_OUT_OF_MEMORY;
+ if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
{
- ALeffect *effect = calloc(1, sizeof(ALeffect));
- err = AL_OUT_OF_MEMORY;
- if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
- {
- free(effect);
- al_throwerr(Context, err);
- }
-
- err = NewThunkEntry(&effect->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(effect->id);
- memset(effect, 0, sizeof(ALeffect));
- free(effect);
+ free(effect);
+ alDeleteEffects(cur, effects);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
- al_throwerr(Context, err);
- }
+ err = NewThunkEntry(&effect->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect);
+ if(err != AL_NO_ERROR)
+ {
+ FreeThunkEntry(effect->id);
+ memset(effect, 0, sizeof(ALeffect));
+ free(effect);
- effects[cur] = effect->id;
- }
- }
- al_catchany()
- {
- if(cur > 0)
alDeleteEffects(cur, effects);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ effects[cur] = effect->id;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
{
- ALCcontext *Context;
- ALeffect *Effect;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALeffect *effect;
ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(effects[i] && LookupEffect(device, effects[i]) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- for(i = 0;i < n;i++)
- {
- if((Effect=RemoveEffect(device, effects[i])) == NULL)
- continue;
- FreeThunkEntry(Effect->id);
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ if(effects[i] && LookupEffect(device, effects[i]) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
+ for(i = 0;i < n;i++)
+ {
+ if((effect=RemoveEffect(device, effects[i])) == NULL)
+ continue;
+ FreeThunkEntry(effect->id);
- memset(Effect, 0, sizeof(*Effect));
- free(Effect);
- }
+ memset(effect, 0, sizeof(*effect));
+ free(effect);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
@@ -170,7 +167,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
else
{
/* Call the appropriate handler */
- ALeffect_SetParami(ALEffect, Context, param, value);
+ V(ALEffect,setParami)(Context, param, value);
}
}
@@ -199,7 +196,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v
else
{
/* Call the appropriate handler */
- ALeffect_SetParamiv(ALEffect, Context, param, values);
+ V(ALEffect,setParamiv)(Context, param, values);
}
ALCcontext_DecRef(Context);
@@ -220,7 +217,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
else
{
/* Call the appropriate handler */
- ALeffect_SetParamf(ALEffect, Context, param, value);
+ V(ALEffect,setParamf)(Context, param, value);
}
ALCcontext_DecRef(Context);
@@ -241,7 +238,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat
else
{
/* Call the appropriate handler */
- ALeffect_SetParamfv(ALEffect, Context, param, values);
+ V(ALEffect,setParamfv)(Context, param, values);
}
ALCcontext_DecRef(Context);
@@ -266,7 +263,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
else
{
/* Call the appropriate handler */
- ALeffect_GetParami(ALEffect, Context, param, value);
+ V(ALEffect,getParami)(Context, param, value);
}
}
@@ -295,7 +292,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu
else
{
/* Call the appropriate handler */
- ALeffect_GetParamiv(ALEffect, Context, param, values);
+ V(ALEffect,getParamiv)(Context, param, values);
}
ALCcontext_DecRef(Context);
@@ -316,7 +313,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val
else
{
/* Call the appropriate handler */
- ALeffect_GetParamf(ALEffect, Context, param, value);
+ V(ALEffect,getParamf)(Context, param, value);
}
ALCcontext_DecRef(Context);
@@ -337,847 +334,13 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va
else
{
/* Call the appropriate handler */
- ALeffect_GetParamfv(ALEffect, Context, param, values);
+ V(ALEffect,getParamfv)(Context, param, values);
}
ALCcontext_DecRef(Context);
}
-static void eaxreverb_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{
- switch(param)
- {
- case AL_EAXREVERB_DECAY_HFLIMIT:
- if(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)
- effect->Reverb.DecayHFLimit = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void eaxreverb_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- eaxreverb_SetParami(effect, context, param, vals[0]);
-}
-static void eaxreverb_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- switch(param)
- {
- case AL_EAXREVERB_DENSITY:
- if(val >= AL_EAXREVERB_MIN_DENSITY &&
- val <= AL_EAXREVERB_MAX_DENSITY)
- effect->Reverb.Density = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_DIFFUSION:
- if(val >= AL_EAXREVERB_MIN_DIFFUSION &&
- val <= AL_EAXREVERB_MAX_DIFFUSION)
- effect->Reverb.Diffusion = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_GAIN:
- if(val >= AL_EAXREVERB_MIN_GAIN &&
- val <= AL_EAXREVERB_MAX_GAIN)
- effect->Reverb.Gain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_GAINHF:
- if(val >= AL_EAXREVERB_MIN_GAINHF &&
- val <= AL_EAXREVERB_MAX_GAINHF)
- effect->Reverb.GainHF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_GAINLF:
- if(val >= AL_EAXREVERB_MIN_GAINLF &&
- val <= AL_EAXREVERB_MAX_GAINLF)
- effect->Reverb.GainLF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_DECAY_TIME:
- if(val >= AL_EAXREVERB_MIN_DECAY_TIME &&
- val <= AL_EAXREVERB_MAX_DECAY_TIME)
- effect->Reverb.DecayTime = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_DECAY_HFRATIO:
- if(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO &&
- val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)
- effect->Reverb.DecayHFRatio = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_DECAY_LFRATIO:
- if(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO &&
- val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)
- effect->Reverb.DecayLFRatio = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_REFLECTIONS_GAIN:
- if(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN &&
- val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)
- effect->Reverb.ReflectionsGain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_REFLECTIONS_DELAY:
- if(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY &&
- val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)
- effect->Reverb.ReflectionsDelay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_LATE_REVERB_GAIN:
- if(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN &&
- val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)
- effect->Reverb.LateReverbGain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_LATE_REVERB_DELAY:
- if(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY &&
- val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)
- effect->Reverb.LateReverbDelay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
- if(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF &&
- val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)
- effect->Reverb.AirAbsorptionGainHF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_ECHO_TIME:
- if(val >= AL_EAXREVERB_MIN_ECHO_TIME &&
- val <= AL_EAXREVERB_MAX_ECHO_TIME)
- effect->Reverb.EchoTime = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_ECHO_DEPTH:
- if(val >= AL_EAXREVERB_MIN_ECHO_DEPTH &&
- val <= AL_EAXREVERB_MAX_ECHO_DEPTH)
- effect->Reverb.EchoDepth = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_MODULATION_TIME:
- if(val >= AL_EAXREVERB_MIN_MODULATION_TIME &&
- val <= AL_EAXREVERB_MAX_MODULATION_TIME)
- effect->Reverb.ModulationTime = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_MODULATION_DEPTH:
- if(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH &&
- val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)
- effect->Reverb.ModulationDepth = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_HFREFERENCE:
- if(val >= AL_EAXREVERB_MIN_HFREFERENCE &&
- val <= AL_EAXREVERB_MAX_HFREFERENCE)
- effect->Reverb.HFReference = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_LFREFERENCE:
- if(val >= AL_EAXREVERB_MIN_LFREFERENCE &&
- val <= AL_EAXREVERB_MAX_LFREFERENCE)
- effect->Reverb.LFReference = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
- if(val >= 0.0f && val <= 10.0f)
- effect->Reverb.RoomRolloffFactor = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void eaxreverb_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- switch(param)
- {
- case AL_EAXREVERB_REFLECTIONS_PAN:
- if(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))
- {
- LockContext(context);
- effect->Reverb.ReflectionsPan[0] = vals[0];
- effect->Reverb.ReflectionsPan[1] = vals[1];
- effect->Reverb.ReflectionsPan[2] = vals[2];
- UnlockContext(context);
- }
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
- case AL_EAXREVERB_LATE_REVERB_PAN:
- if(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))
- {
- LockContext(context);
- effect->Reverb.LateReverbPan[0] = vals[0];
- effect->Reverb.LateReverbPan[1] = vals[1];
- effect->Reverb.LateReverbPan[2] = vals[2];
- UnlockContext(context);
- }
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- eaxreverb_SetParamf(effect, context, param, vals[0]);
- break;
- }
-}
-
-static void eaxreverb_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{
- switch(param)
- {
- case AL_EAXREVERB_DECAY_HFLIMIT:
- *val = effect->Reverb.DecayHFLimit;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void eaxreverb_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- eaxreverb_GetParami(effect, context, param, vals);
-}
-static void eaxreverb_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- switch(param)
- {
- case AL_EAXREVERB_DENSITY:
- *val = effect->Reverb.Density;
- break;
-
- case AL_EAXREVERB_DIFFUSION:
- *val = effect->Reverb.Diffusion;
- break;
-
- case AL_EAXREVERB_GAIN:
- *val = effect->Reverb.Gain;
- break;
-
- case AL_EAXREVERB_GAINHF:
- *val = effect->Reverb.GainHF;
- break;
-
- case AL_EAXREVERB_GAINLF:
- *val = effect->Reverb.GainLF;
- break;
-
- case AL_EAXREVERB_DECAY_TIME:
- *val = effect->Reverb.DecayTime;
- break;
-
- case AL_EAXREVERB_DECAY_HFRATIO:
- *val = effect->Reverb.DecayHFRatio;
- break;
-
- case AL_EAXREVERB_DECAY_LFRATIO:
- *val = effect->Reverb.DecayLFRatio;
- break;
-
- case AL_EAXREVERB_REFLECTIONS_GAIN:
- *val = effect->Reverb.ReflectionsGain;
- break;
-
- case AL_EAXREVERB_REFLECTIONS_DELAY:
- *val = effect->Reverb.ReflectionsDelay;
- break;
-
- case AL_EAXREVERB_LATE_REVERB_GAIN:
- *val = effect->Reverb.LateReverbGain;
- break;
-
- case AL_EAXREVERB_LATE_REVERB_DELAY:
- *val = effect->Reverb.LateReverbDelay;
- break;
-
- case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
- *val = effect->Reverb.AirAbsorptionGainHF;
- break;
-
- case AL_EAXREVERB_ECHO_TIME:
- *val = effect->Reverb.EchoTime;
- break;
-
- case AL_EAXREVERB_ECHO_DEPTH:
- *val = effect->Reverb.EchoDepth;
- break;
-
- case AL_EAXREVERB_MODULATION_TIME:
- *val = effect->Reverb.ModulationTime;
- break;
-
- case AL_EAXREVERB_MODULATION_DEPTH:
- *val = effect->Reverb.ModulationDepth;
- break;
-
- case AL_EAXREVERB_HFREFERENCE:
- *val = effect->Reverb.HFReference;
- break;
-
- case AL_EAXREVERB_LFREFERENCE:
- *val = effect->Reverb.LFReference;
- break;
-
- case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
- *val = effect->Reverb.RoomRolloffFactor;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void eaxreverb_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- switch(param)
- {
- case AL_EAXREVERB_REFLECTIONS_PAN:
- LockContext(context);
- vals[0] = effect->Reverb.ReflectionsPan[0];
- vals[1] = effect->Reverb.ReflectionsPan[1];
- vals[2] = effect->Reverb.ReflectionsPan[2];
- UnlockContext(context);
- break;
- case AL_EAXREVERB_LATE_REVERB_PAN:
- LockContext(context);
- vals[0] = effect->Reverb.LateReverbPan[0];
- vals[1] = effect->Reverb.LateReverbPan[1];
- vals[2] = effect->Reverb.LateReverbPan[2];
- UnlockContext(context);
- break;
-
- default:
- eaxreverb_GetParamf(effect, context, param, vals);
- break;
- }
-}
-
-
-static void reverb_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{
- switch(param)
- {
- case AL_REVERB_DECAY_HFLIMIT:
- if(val >= AL_REVERB_MIN_DECAY_HFLIMIT &&
- val <= AL_REVERB_MAX_DECAY_HFLIMIT)
- effect->Reverb.DecayHFLimit = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void reverb_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- reverb_SetParami(effect, context, param, vals[0]);
-}
-static void reverb_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- switch(param)
- {
- case AL_REVERB_DENSITY:
- if(val >= AL_REVERB_MIN_DENSITY &&
- val <= AL_REVERB_MAX_DENSITY)
- effect->Reverb.Density = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_DIFFUSION:
- if(val >= AL_REVERB_MIN_DIFFUSION &&
- val <= AL_REVERB_MAX_DIFFUSION)
- effect->Reverb.Diffusion = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_GAIN:
- if(val >= AL_REVERB_MIN_GAIN &&
- val <= AL_REVERB_MAX_GAIN)
- effect->Reverb.Gain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_GAINHF:
- if(val >= AL_REVERB_MIN_GAINHF &&
- val <= AL_REVERB_MAX_GAINHF)
- effect->Reverb.GainHF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_DECAY_TIME:
- if(val >= AL_REVERB_MIN_DECAY_TIME &&
- val <= AL_REVERB_MAX_DECAY_TIME)
- effect->Reverb.DecayTime = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_DECAY_HFRATIO:
- if(val >= AL_REVERB_MIN_DECAY_HFRATIO &&
- val <= AL_REVERB_MAX_DECAY_HFRATIO)
- effect->Reverb.DecayHFRatio = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_REFLECTIONS_GAIN:
- if(val >= AL_REVERB_MIN_REFLECTIONS_GAIN &&
- val <= AL_REVERB_MAX_REFLECTIONS_GAIN)
- effect->Reverb.ReflectionsGain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_REFLECTIONS_DELAY:
- if(val >= AL_REVERB_MIN_REFLECTIONS_DELAY &&
- val <= AL_REVERB_MAX_REFLECTIONS_DELAY)
- effect->Reverb.ReflectionsDelay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_LATE_REVERB_GAIN:
- if(val >= AL_REVERB_MIN_LATE_REVERB_GAIN &&
- val <= AL_REVERB_MAX_LATE_REVERB_GAIN)
- effect->Reverb.LateReverbGain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_LATE_REVERB_DELAY:
- if(val >= AL_REVERB_MIN_LATE_REVERB_DELAY &&
- val <= AL_REVERB_MAX_LATE_REVERB_DELAY)
- effect->Reverb.LateReverbDelay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_AIR_ABSORPTION_GAINHF:
- if(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF &&
- val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)
- effect->Reverb.AirAbsorptionGainHF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_REVERB_ROOM_ROLLOFF_FACTOR:
- if(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR &&
- val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)
- effect->Reverb.RoomRolloffFactor = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void reverb_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- reverb_SetParamf(effect, context, param, vals[0]);
-}
-
-static void reverb_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{
- switch(param)
- {
- case AL_REVERB_DECAY_HFLIMIT:
- *val = effect->Reverb.DecayHFLimit;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void reverb_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- reverb_GetParami(effect, context, param, vals);
-}
-static void reverb_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- switch(param)
- {
- case AL_REVERB_DENSITY:
- *val = effect->Reverb.Density;
- break;
-
- case AL_REVERB_DIFFUSION:
- *val = effect->Reverb.Diffusion;
- break;
-
- case AL_REVERB_GAIN:
- *val = effect->Reverb.Gain;
- break;
-
- case AL_REVERB_GAINHF:
- *val = effect->Reverb.GainHF;
- break;
-
- case AL_REVERB_DECAY_TIME:
- *val = effect->Reverb.DecayTime;
- break;
-
- case AL_REVERB_DECAY_HFRATIO:
- *val = effect->Reverb.DecayHFRatio;
- break;
-
- case AL_REVERB_REFLECTIONS_GAIN:
- *val = effect->Reverb.ReflectionsGain;
- break;
-
- case AL_REVERB_REFLECTIONS_DELAY:
- *val = effect->Reverb.ReflectionsDelay;
- break;
-
- case AL_REVERB_LATE_REVERB_GAIN:
- *val = effect->Reverb.LateReverbGain;
- break;
-
- case AL_REVERB_LATE_REVERB_DELAY:
- *val = effect->Reverb.LateReverbDelay;
- break;
-
- case AL_REVERB_AIR_ABSORPTION_GAINHF:
- *val = effect->Reverb.AirAbsorptionGainHF;
- break;
-
- case AL_REVERB_ROOM_ROLLOFF_FACTOR:
- *val = effect->Reverb.RoomRolloffFactor;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void reverb_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- reverb_GetParamf(effect, context, param, vals);
-}
-
-
-static void echo_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void echo_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- echo_SetParami(effect, context, param, vals[0]);
-}
-static void echo_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- switch(param)
- {
- case AL_ECHO_DELAY:
- if(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)
- effect->Echo.Delay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_ECHO_LRDELAY:
- if(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)
- effect->Echo.LRDelay = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_ECHO_DAMPING:
- if(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)
- effect->Echo.Damping = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_ECHO_FEEDBACK:
- if(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)
- effect->Echo.Feedback = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_ECHO_SPREAD:
- if(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)
- effect->Echo.Spread = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void echo_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- echo_SetParamf(effect, context, param, vals[0]);
-}
-
-static void echo_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void echo_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- echo_GetParami(effect, context, param, vals);
-}
-static void echo_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- switch(param)
- {
- case AL_ECHO_DELAY:
- *val = effect->Echo.Delay;
- break;
-
- case AL_ECHO_LRDELAY:
- *val = effect->Echo.LRDelay;
- break;
-
- case AL_ECHO_DAMPING:
- *val = effect->Echo.Damping;
- break;
-
- case AL_ECHO_FEEDBACK:
- *val = effect->Echo.Feedback;
- break;
-
- case AL_ECHO_SPREAD:
- *val = effect->Echo.Spread;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void echo_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- echo_GetParamf(effect, context, param, vals);
-}
-
-
-static void mod_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- switch(param)
- {
- case AL_RING_MODULATOR_FREQUENCY:
- if(val >= AL_RING_MODULATOR_MIN_FREQUENCY &&
- val <= AL_RING_MODULATOR_MAX_FREQUENCY)
- effect->Modulator.Frequency = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- if(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF &&
- val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)
- effect->Modulator.HighPassCutoff = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void mod_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- mod_SetParamf(effect, context, param, vals[0]);
-}
-static void mod_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{
- switch(param)
- {
- case AL_RING_MODULATOR_FREQUENCY:
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- mod_SetParamf(effect, context, param, (ALfloat)val);
- break;
-
- case AL_RING_MODULATOR_WAVEFORM:
- if(val >= AL_RING_MODULATOR_MIN_WAVEFORM &&
- val <= AL_RING_MODULATOR_MAX_WAVEFORM)
- effect->Modulator.Waveform = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void mod_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- mod_SetParami(effect, context, param, vals[0]);
-}
-
-static void mod_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{
- switch(param)
- {
- case AL_RING_MODULATOR_FREQUENCY:
- *val = (ALint)effect->Modulator.Frequency;
- break;
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- *val = (ALint)effect->Modulator.HighPassCutoff;
- break;
- case AL_RING_MODULATOR_WAVEFORM:
- *val = effect->Modulator.Waveform;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void mod_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- mod_GetParami(effect, context, param, vals);
-}
-static void mod_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- switch(param)
- {
- case AL_RING_MODULATOR_FREQUENCY:
- *val = effect->Modulator.Frequency;
- break;
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- *val = effect->Modulator.HighPassCutoff;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void mod_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- mod_GetParamf(effect, context, param, vals);
-}
-
-
-static void ded_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void ded_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
- ded_SetParami(effect, context, param, vals[0]);
-}
-static void ded_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
- switch(param)
- {
- case AL_DEDICATED_GAIN:
- if(val >= 0.0f && isfinite(val))
- effect->Dedicated.Gain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void ded_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
- ded_SetParamf(effect, context, param, vals[0]);
-}
-
-static void ded_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void ded_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
- ded_GetParami(effect, context, param, vals);
-}
-static void ded_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
- switch(param)
- {
- case AL_DEDICATED_GAIN:
- *val = effect->Dedicated.Gain;
- break;
-
- default:
- alSetError(context, AL_INVALID_ENUM);
- break;
- }
-}
-static void ded_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
- ded_GetParamf(effect, context, param, vals);
-}
-
-
-static void null_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-
-static void null_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-
-
ALenum InitEffect(ALeffect *effect)
{
InitEffectParams(effect, AL_EFFECT_NULL);
@@ -1205,114 +368,122 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
switch(type)
{
case AL_EFFECT_EAXREVERB:
- effect->Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
- effect->Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
- effect->Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
- effect->Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
- effect->Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
- effect->Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
- effect->Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
- effect->Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
- effect->Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
- effect->Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
- effect->Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- effect->Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- effect->Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- effect->Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
- effect->Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
- effect->Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- effect->Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- effect->Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- effect->Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
- effect->Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
- effect->Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
- effect->Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
- effect->Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
- effect->Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
- effect->Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
- effect->Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
- effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
- effect->SetParami = eaxreverb_SetParami;
- effect->SetParamiv = eaxreverb_SetParamiv;
- effect->SetParamf = eaxreverb_SetParamf;
- effect->SetParamfv = eaxreverb_SetParamfv;
- effect->GetParami = eaxreverb_GetParami;
- effect->GetParamiv = eaxreverb_GetParamiv;
- effect->GetParamf = eaxreverb_GetParamf;
- effect->GetParamfv = eaxreverb_GetParamfv;
+ effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
+ effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
+ effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
+ effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
+ effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
+ effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
+ effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
+ effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
+ effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
+ effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
+ effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
+ effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
+ effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
+ effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
+ effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
+ effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
+ effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
+ effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
+ effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+ effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
+ SET_VTABLE1(ALeaxreverb, effect);
break;
case AL_EFFECT_REVERB:
- effect->Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
- effect->Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
- effect->Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
- effect->Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
- effect->Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
- effect->Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
- effect->Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
- effect->Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
- effect->Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
- effect->Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
- effect->Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
- effect->Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
- effect->Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
- effect->SetParami = reverb_SetParami;
- effect->SetParamiv = reverb_SetParamiv;
- effect->SetParamf = reverb_SetParamf;
- effect->SetParamfv = reverb_SetParamfv;
- effect->GetParami = reverb_GetParami;
- effect->GetParamiv = reverb_GetParamiv;
- effect->GetParamf = reverb_GetParamf;
- effect->GetParamfv = reverb_GetParamfv;
+ effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
+ effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
+ effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
+ effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
+ effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
+ effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
+ effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
+ effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
+ effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
+ effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
+ effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+ effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
+ SET_VTABLE1(ALreverb, effect);
+ break;
+ case AL_EFFECT_AUTOWAH:
+ effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
+ effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
+ effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
+ effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
+ SET_VTABLE1(ALautowah, effect);
+ break;
+ case AL_EFFECT_CHORUS:
+ effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
+ effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
+ effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
+ effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
+ effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
+ effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
+ SET_VTABLE1(ALchorus, effect);
+ break;
+ case AL_EFFECT_COMPRESSOR:
+ effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
+ SET_VTABLE1(ALcompressor, effect);
+ break;
+ case AL_EFFECT_DISTORTION:
+ effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
+ effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
+ effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
+ effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
+ effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
+ SET_VTABLE1(ALdistortion, effect);
break;
case AL_EFFECT_ECHO:
- effect->Echo.Delay = AL_ECHO_DEFAULT_DELAY;
- effect->Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
- effect->Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
- effect->Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
- effect->Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
- effect->SetParami = echo_SetParami;
- effect->SetParamiv = echo_SetParamiv;
- effect->SetParamf = echo_SetParamf;
- effect->SetParamfv = echo_SetParamfv;
- effect->GetParami = echo_GetParami;
- effect->GetParamiv = echo_GetParamiv;
- effect->GetParamf = echo_GetParamf;
- effect->GetParamfv = echo_GetParamfv;
+ effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
+ effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
+ effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
+ effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
+ effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
+ SET_VTABLE1(ALecho, effect);
+ break;
+ case AL_EFFECT_EQUALIZER:
+ effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
+ effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
+ effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
+ effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
+ effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
+ effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
+ effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
+ effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
+ effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
+ effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
+ SET_VTABLE1(ALequalizer, effect);
+ break;
+ case AL_EFFECT_FLANGER:
+ effect->Props.Flanger.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
+ effect->Props.Flanger.Phase = AL_FLANGER_DEFAULT_PHASE;
+ effect->Props.Flanger.Rate = AL_FLANGER_DEFAULT_RATE;
+ effect->Props.Flanger.Depth = AL_FLANGER_DEFAULT_DEPTH;
+ effect->Props.Flanger.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
+ effect->Props.Flanger.Delay = AL_FLANGER_DEFAULT_DELAY;
+ SET_VTABLE1(ALflanger, effect);
break;
case AL_EFFECT_RING_MODULATOR:
- effect->Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
- effect->Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
- effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
- effect->SetParami = mod_SetParami;
- effect->SetParamiv = mod_SetParamiv;
- effect->SetParamf = mod_SetParamf;
- effect->SetParamfv = mod_SetParamfv;
- effect->GetParami = mod_GetParami;
- effect->GetParamiv = mod_GetParamiv;
- effect->GetParamf = mod_GetParamf;
- effect->GetParamfv = mod_GetParamfv;
+ effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
+ effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
+ effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
+ SET_VTABLE1(ALmodulator, effect);
break;
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
case AL_EFFECT_DEDICATED_DIALOGUE:
- effect->Dedicated.Gain = 1.0f;
- effect->SetParami = ded_SetParami;
- effect->SetParamiv = ded_SetParamiv;
- effect->SetParamf = ded_SetParamf;
- effect->SetParamfv = ded_SetParamfv;
- effect->GetParami = ded_GetParami;
- effect->GetParamiv = ded_GetParamiv;
- effect->GetParamf = ded_GetParamf;
- effect->GetParamfv = ded_GetParamfv;
+ effect->Props.Dedicated.Gain = 1.0f;
+ SET_VTABLE1(ALdedicated, effect);
break;
default:
- effect->SetParami = null_SetParami;
- effect->SetParamiv = null_SetParamiv;
- effect->SetParamf = null_SetParamf;
- effect->SetParamfv = null_SetParamfv;
- effect->GetParami = null_GetParami;
- effect->GetParamiv = null_GetParamiv;
- effect->GetParamf = null_GetParamf;
- effect->GetParamfv = null_GetParamfv;
+ SET_VTABLE1(ALnull, effect);
break;
}
effect->type = type;
@@ -1454,11 +625,10 @@ static const struct {
DECL(SMALLWATERROOM),
};
#undef DECL
-static const ALsizei reverblistsize = COUNTOF(reverblist);
ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
{
- int i;
+ size_t i;
if(strcasecmp(name, "NONE") == 0)
{
@@ -1473,7 +643,7 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
- for(i = 0;i < reverblistsize;i++)
+ for(i = 0;i < COUNTOF(reverblist);i++)
{
const EFXEAXREVERBPROPERTIES *props;
@@ -1482,35 +652,35 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
TRACE("Loading reverb '%s'\n", reverblist[i].name);
props = &reverblist[i].props;
- effect->Reverb.Density = props->flDensity;
- effect->Reverb.Diffusion = props->flDiffusion;
- effect->Reverb.Gain = props->flGain;
- effect->Reverb.GainHF = props->flGainHF;
- effect->Reverb.GainLF = props->flGainLF;
- effect->Reverb.DecayTime = props->flDecayTime;
- effect->Reverb.DecayHFRatio = props->flDecayHFRatio;
- effect->Reverb.DecayLFRatio = props->flDecayLFRatio;
- effect->Reverb.ReflectionsGain = props->flReflectionsGain;
- effect->Reverb.ReflectionsDelay = props->flReflectionsDelay;
- effect->Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
- effect->Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
- effect->Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
- effect->Reverb.LateReverbGain = props->flLateReverbGain;
- effect->Reverb.LateReverbDelay = props->flLateReverbDelay;
- effect->Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
- effect->Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
- effect->Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
- effect->Reverb.EchoTime = props->flEchoTime;
- effect->Reverb.EchoDepth = props->flEchoDepth;
- effect->Reverb.ModulationTime = props->flModulationTime;
- effect->Reverb.ModulationDepth = props->flModulationDepth;
- effect->Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
- effect->Reverb.HFReference = props->flHFReference;
- effect->Reverb.LFReference = props->flLFReference;
- effect->Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
- effect->Reverb.DecayHFLimit = props->iDecayHFLimit;
- break;
+ effect->Props.Reverb.Density = props->flDensity;
+ effect->Props.Reverb.Diffusion = props->flDiffusion;
+ effect->Props.Reverb.Gain = props->flGain;
+ effect->Props.Reverb.GainHF = props->flGainHF;
+ effect->Props.Reverb.GainLF = props->flGainLF;
+ effect->Props.Reverb.DecayTime = props->flDecayTime;
+ effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
+ effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
+ effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
+ effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
+ effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
+ effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
+ effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
+ effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
+ effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
+ effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
+ effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
+ effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
+ effect->Props.Reverb.EchoTime = props->flEchoTime;
+ effect->Props.Reverb.EchoDepth = props->flEchoDepth;
+ effect->Props.Reverb.ModulationTime = props->flModulationTime;
+ effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
+ effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
+ effect->Props.Reverb.HFReference = props->flHFReference;
+ effect->Props.Reverb.LFReference = props->flLFReference;
+ effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
+ effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit;
+ return;
}
- if(i == reverblistsize)
- WARN("Reverb preset '%s' not found\n", name);
+
+ WARN("Reverb preset '%s' not found\n", name);
}
diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c
index d18c1867..b557532e 100644
--- a/OpenAL32/alError.c
+++ b/OpenAL32/alError.c
@@ -22,6 +22,11 @@
#include <signal.h>
+#ifdef HAVE_WINDOWS_H
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c
index c73200d0..fc23a932 100644
--- a/OpenAL32/alExtension.c
+++ b/OpenAL32/alExtension.c
@@ -36,12 +36,18 @@
const struct EffectList EffectList[] = {
- { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
- { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
- { "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
- { "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
- { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
- { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE },
+ { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
+ { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
+ { "autowah", AUTOWAH, "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH },
+ { "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
+ { "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
+ { "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
+ { "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
+ { "equalizer", EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
+ { "flanger", FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
+ { "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
+ { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
+ { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE },
{ NULL, 0, NULL, (ALenum)0 }
};
@@ -49,38 +55,36 @@ const struct EffectList EffectList[] = {
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
{
ALboolean ret = AL_FALSE;
- ALCcontext *Context;
+ ALCcontext *context;
const char *ptr;
size_t len;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- al_try
- {
- CHECK_VALUE(Context, extName);
+ if(!(extName))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- len = strlen(extName);
- ptr = Context->ExtensionList;
- while(ptr && *ptr)
+ len = strlen(extName);
+ ptr = context->ExtensionList;
+ while(ptr && *ptr)
+ {
+ if(strncasecmp(ptr, extName, len) == 0 &&
+ (ptr[len] == '\0' || isspace(ptr[len])))
+ {
+ ret = AL_TRUE;
+ break;
+ }
+ if((ptr=strchr(ptr, ' ')) != NULL)
{
- if(strncasecmp(ptr, extName, len) == 0 &&
- (ptr[len] == '\0' || isspace(ptr[len])))
- {
- ret = AL_TRUE;
- break;
- }
- if((ptr=strchr(ptr, ' ')) != NULL)
- {
- do {
- ++ptr;
- } while(isspace(*ptr));
- }
+ do {
+ ++ptr;
+ } while(isspace(*ptr));
}
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return ret;
}
diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c
index a03ee2d8..692109f5 100644
--- a/OpenAL32/alFilter.c
+++ b/OpenAL32/alFilter.c
@@ -29,87 +29,89 @@
#include "alError.h"
+extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
+extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
+extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
+extern inline ALfloat ALfilterState_processSingleC(const ALfilterState *filter, ALfloat sample);
+
static void InitFilterParams(ALfilter *filter, ALenum type);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
- ALCcontext *Context;
- ALsizei cur = 0;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsizei cur = 0;
+ ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- ALenum err;
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- CHECK_VALUE(Context, n >= 0);
- for(cur = 0;cur < n;cur++)
+ device = context->Device;
+ for(cur = 0;cur < n;cur++)
+ {
+ ALfilter *filter = calloc(1, sizeof(ALfilter));
+ if(!filter)
{
- ALfilter *filter = calloc(1, sizeof(ALfilter));
- if(!filter)
- al_throwerr(Context, AL_OUT_OF_MEMORY);
- InitFilterParams(filter, AL_FILTER_NULL);
-
- err = NewThunkEntry(&filter->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(filter->id);
- memset(filter, 0, sizeof(ALfilter));
- free(filter);
-
- al_throwerr(Context, err);
- }
-
- filters[cur] = filter->id;
+ alDeleteFilters(cur, filters);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
- }
- al_catchany()
- {
- if(cur > 0)
+ InitFilterParams(filter, AL_FILTER_NULL);
+
+ err = NewThunkEntry(&filter->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter);
+ if(err != AL_NO_ERROR)
+ {
+ FreeThunkEntry(filter->id);
+ memset(filter, 0, sizeof(ALfilter));
+ free(filter);
+
alDeleteFilters(cur, filters);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ filters[cur] = filter->id;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
{
- ALCcontext *Context;
- ALfilter *Filter;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfilter *filter;
ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(filters[i] && LookupFilter(device, filters[i]) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- for(i = 0;i < n;i++)
- {
- if((Filter=RemoveFilter(device, filters[i])) == NULL)
- continue;
- FreeThunkEntry(Filter->id);
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ if(filters[i] && LookupFilter(device, filters[i]) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
+ for(i = 0;i < n;i++)
+ {
+ if((filter=RemoveFilter(device, filters[i])) == NULL)
+ continue;
+ FreeThunkEntry(filter->id);
- memset(Filter, 0, sizeof(*Filter));
- free(Filter);
- }
+ memset(filter, 0, sizeof(*filter));
+ free(filter);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
@@ -326,48 +328,137 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va
}
-ALfloat lpCoeffCalc(ALfloat g, ALfloat cw)
+void ALfilterState_clear(ALfilterState *filter)
{
- ALfloat a = 0.0f;
+ filter->x[0] = 0.0f;
+ filter->x[1] = 0.0f;
+ filter->y[0] = 0.0f;
+ filter->y[1] = 0.0f;
+}
- if(g < 0.9999f) /* 1-epsilon */
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_scale, ALfloat bandwidth)
+{
+ ALfloat alpha;
+ ALfloat w0;
+
+ // Limit gain to -100dB
+ gain = maxf(gain, 0.00001f);
+
+ w0 = F_2PI * freq_scale;
+
+ /* Calculate filter coefficients depending on filter type */
+ switch(type)
{
- /* Be careful with gains < 0.001, as that causes the coefficient head
- * towards 1, which will flatten the signal */
- g = maxf(g, 0.001f);
- a = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) /
- (1 - g);
+ case ALfilterType_HighShelf:
+ alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f/gain) *
+ (1.0f/0.75f - 1.0f) + 2.0f);
+ filter->b[0] = gain * ((gain + 1.0f) +
+ (gain - 1.0f) * cosf(w0) +
+ 2.0f * sqrtf(gain) * alpha);
+ filter->b[1] = -2.0f * gain * ((gain - 1.0f) +
+ (gain + 1.0f) * cosf(w0));
+ filter->b[2] = gain * ((gain + 1.0f) +
+ (gain - 1.0f) * cosf(w0) -
+ 2.0f * sqrtf(gain) * alpha);
+ filter->a[0] = (gain + 1.0f) -
+ (gain - 1.0f) * cosf(w0) +
+ 2.0f * sqrtf(gain) * alpha;
+ filter->a[1] = 2.0f * ((gain - 1.0f) -
+ (gain + 1.0f) * cosf(w0));
+ filter->a[2] = (gain + 1.0f) -
+ (gain - 1.0f) * cosf(w0) -
+ 2.0f * sqrtf(gain) * alpha;
+ break;
+ case ALfilterType_LowShelf:
+ alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) *
+ (1.0f / 0.75f - 1.0f) + 2.0f);
+ filter->b[0] = gain * ((gain + 1.0f) -
+ (gain - 1.0f) * cosf(w0) +
+ 2.0f * sqrtf(gain) * alpha);
+ filter->b[1] = 2.0f * gain * ((gain - 1.0f) -
+ (gain + 1.0f) * cosf(w0));
+ filter->b[2] = gain * ((gain + 1.0f) -
+ (gain - 1.0f) * cosf(w0) -
+ 2.0f * sqrtf(gain) * alpha);
+ filter->a[0] = (gain + 1.0f) +
+ (gain - 1.0f) * cosf(w0) +
+ 2.0f * sqrtf(gain) * alpha;
+ filter->a[1] = -2.0f * ((gain - 1.0f) +
+ (gain + 1.0f) * cosf(w0));
+ filter->a[2] = (gain + 1.0f) +
+ (gain - 1.0f) * cosf(w0) -
+ 2.0f * sqrtf(gain) * alpha;
+ break;
+ case ALfilterType_Peaking:
+ alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+ filter->b[0] = 1.0f + alpha * gain;
+ filter->b[1] = -2.0f * cosf(w0);
+ filter->b[2] = 1.0f - alpha * gain;
+ filter->a[0] = 1.0f + alpha / gain;
+ filter->a[1] = -2.0f * cosf(w0);
+ filter->a[2] = 1.0f - alpha / gain;
+ break;
+
+ case ALfilterType_LowPass:
+ alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+ filter->b[0] = (1.0f - cosf(w0)) / 2.0f;
+ filter->b[1] = 1.0f - cosf(w0);
+ filter->b[2] = (1.0f - cosf(w0)) / 2.0f;
+ filter->a[0] = 1.0f + alpha;
+ filter->a[1] = -2.0f * cosf(w0);
+ filter->a[2] = 1.0f - alpha;
+ break;
+ case ALfilterType_HighPass:
+ alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+ filter->b[0] = (1.0f + cosf(w0)) / 2.0f;
+ filter->b[1] = 1.0f + cosf(w0);
+ filter->b[2] = (1.0f + cosf(w0)) / 2.0f;
+ filter->a[0] = 1.0f + alpha;
+ filter->a[1] = -2.0f * cosf(w0);
+ filter->a[2] = 1.0f - alpha;
+ break;
+ case ALfilterType_BandPass:
+ alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+ filter->b[0] = alpha;
+ filter->b[1] = 0;
+ filter->b[2] = -alpha;
+ filter->a[0] = 1.0f + alpha;
+ filter->a[1] = -2.0f * cosf(w0);
+ filter->a[2] = 1.0f - alpha;
+ break;
}
- return a;
+ filter->b[2] /= filter->a[0];
+ filter->b[1] /= filter->a[0];
+ filter->b[0] /= filter->a[0];
+ filter->a[2] /= filter->a[0];
+ filter->a[1] /= filter->a[0];
+ filter->a[0] /= filter->a[0];
}
-static void lp_SetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void lp_SetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
+static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void lp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_LOWPASS_GAIN:
- if(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN)
- filter->Gain = val;
- else
- alSetError(context, AL_INVALID_VALUE);
+ if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ filter->Gain = val;
break;
case AL_LOWPASS_GAINHF:
- if(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)
- filter->GainHF = val;
- else
- alSetError(context, AL_INVALID_VALUE);
+ if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ filter->GainHF = val;
break;
default:
- alSetError(context, AL_INVALID_ENUM);
- break;
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
@@ -375,10 +466,10 @@ static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, c
lp_SetParamf(filter, context, param, vals[0]);
}
-static void lp_GetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void lp_GetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
+static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void lp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
@@ -392,8 +483,7 @@ static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL
break;
default:
- alSetError(context, AL_INVALID_ENUM);
- break;
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
@@ -402,23 +492,23 @@ static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, A
}
-static void null_SetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-
-static void null_GetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
-{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); }
-static void null_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
-{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
+static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_SetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_SetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+
+static void null_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_GetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+static void null_GetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals))
+{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
ALvoid ReleaseALFilters(ALCdevice *device)
diff --git a/OpenAL32/alFontsound.c b/OpenAL32/alFontsound.c
new file mode 100644
index 00000000..94cf3064
--- /dev/null
+++ b/OpenAL32/alFontsound.c
@@ -0,0 +1,972 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "alMain.h"
+#include "alMidi.h"
+#include "alError.h"
+#include "alThunk.h"
+
+#include "midi/base.h"
+
+
+extern inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id);
+extern inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id);
+
+static void ALfontsound_Construct(ALfontsound *self);
+void ALfontsound_Destruct(ALfontsound *self);
+void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value);
+static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage);
+void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value);
+static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values);
+
+
+AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids)
+{
+ ALCcontext *context;
+ ALsizei cur = 0;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ for(cur = 0;cur < n;cur++)
+ {
+ ALfontsound *sound = NewFontsound(context);
+ if(!sound)
+ {
+ alDeleteFontsoundsSOFT(cur, ids);
+ break;
+ }
+
+ ids[cur] = sound->id;
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *inst;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ /* Check for valid ID */
+ if((inst=LookupFontsound(device, ids[i])) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(inst->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ if((inst=RemoveFontsound(device, ids[i])) == NULL)
+ continue;
+
+ ALfontsound_Destruct(inst);
+
+ memset(inst, 0, sizeof(*inst));
+ free(inst);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id)
+{
+ ALCcontext *context;
+ ALboolean ret;
+
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
+
+ ret = LookupFontsound(context->Device, id) ? AL_TRUE : AL_FALSE;
+
+ ALCcontext_DecRef(context);
+
+ return ret;
+}
+
+AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *sound;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(sound->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+
+ ALfontsound_setPropi(sound, context, param, value);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *sound;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(sound->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ switch(param)
+ {
+ case AL_KEY_RANGE_SOFT:
+ if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ sound->MinKey = value1;
+ sound->MaxKey = value2;
+ break;
+
+ case AL_VELOCITY_RANGE_SOFT:
+ if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ sound->MinVelocity = value1;
+ sound->MaxVelocity = value2;
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *sound;
+
+ switch(param)
+ {
+ case AL_KEY_RANGE_SOFT:
+ case AL_VELOCITY_RANGE_SOFT:
+ alFontsound2iSOFT(id, param, values[0], values[1]);
+ return;
+
+ case AL_MOD_LFO_TO_PITCH_SOFT:
+ case AL_VIBRATO_LFO_TO_PITCH_SOFT:
+ case AL_MOD_ENV_TO_PITCH_SOFT:
+ case AL_FILTER_CUTOFF_SOFT:
+ case AL_FILTER_RESONANCE_SOFT:
+ case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
+ case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
+ case AL_MOD_LFO_TO_VOLUME_SOFT:
+ case AL_CHORUS_SEND_SOFT:
+ case AL_REVERB_SEND_SOFT:
+ case AL_PAN_SOFT:
+ case AL_MOD_LFO_DELAY_SOFT:
+ case AL_MOD_LFO_FREQUENCY_SOFT:
+ case AL_VIBRATO_LFO_DELAY_SOFT:
+ case AL_VIBRATO_LFO_FREQUENCY_SOFT:
+ case AL_MOD_ENV_DELAYTIME_SOFT:
+ case AL_MOD_ENV_ATTACKTIME_SOFT:
+ case AL_MOD_ENV_HOLDTIME_SOFT:
+ case AL_MOD_ENV_DECAYTIME_SOFT:
+ case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
+ case AL_MOD_ENV_RELEASETIME_SOFT:
+ case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
+ case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
+ case AL_VOLUME_ENV_DELAYTIME_SOFT:
+ case AL_VOLUME_ENV_ATTACKTIME_SOFT:
+ case AL_VOLUME_ENV_HOLDTIME_SOFT:
+ case AL_VOLUME_ENV_DECAYTIME_SOFT:
+ case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
+ case AL_VOLUME_ENV_RELEASETIME_SOFT:
+ case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
+ case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
+ case AL_ATTENUATION_SOFT:
+ case AL_TUNING_COARSE_SOFT:
+ case AL_TUNING_FINE_SOFT:
+ case AL_LOOP_MODE_SOFT:
+ case AL_TUNING_SCALE_SOFT:
+ case AL_EXCLUSIVE_CLASS_SOFT:
+ case AL_SAMPLE_START_SOFT:
+ case AL_SAMPLE_END_SOFT:
+ case AL_SAMPLE_LOOP_START_SOFT:
+ case AL_SAMPLE_LOOP_END_SOFT:
+ case AL_SAMPLE_RATE_SOFT:
+ case AL_BASE_KEY_SOFT:
+ case AL_KEY_CORRECTION_SOFT:
+ case AL_SAMPLE_TYPE_SOFT:
+ case AL_FONTSOUND_LINK_SOFT:
+ alFontsoundiSOFT(id, param, values[0]);
+ return;
+ }
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(sound->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ const ALfontsound *sound;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
+ {
+ case AL_MOD_LFO_TO_PITCH_SOFT:
+ values[0] = sound->ModLfoToPitch;
+ break;
+
+ case AL_VIBRATO_LFO_TO_PITCH_SOFT:
+ values[0] = sound->VibratoLfoToPitch;
+ break;
+
+ case AL_MOD_ENV_TO_PITCH_SOFT:
+ values[0] = sound->ModEnvToPitch;
+ break;
+
+ case AL_FILTER_CUTOFF_SOFT:
+ values[0] = sound->FilterCutoff;
+ break;
+
+ case AL_FILTER_RESONANCE_SOFT:
+ values[0] = sound->FilterQ;
+ break;
+
+ case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
+ values[0] = sound->ModLfoToFilterCutoff;
+ break;
+
+ case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
+ values[0] = sound->ModEnvToFilterCutoff;
+ break;
+
+ case AL_MOD_LFO_TO_VOLUME_SOFT:
+ values[0] = sound->ModLfoToVolume;
+ break;
+
+ case AL_CHORUS_SEND_SOFT:
+ values[0] = sound->ChorusSend;
+ break;
+
+ case AL_REVERB_SEND_SOFT:
+ values[0] = sound->ReverbSend;
+ break;
+
+ case AL_PAN_SOFT:
+ values[0] = sound->Pan;
+ break;
+
+ case AL_MOD_LFO_DELAY_SOFT:
+ values[0] = sound->ModLfo.Delay;
+ break;
+ case AL_MOD_LFO_FREQUENCY_SOFT:
+ values[0] = sound->ModLfo.Frequency;
+ break;
+
+ case AL_VIBRATO_LFO_DELAY_SOFT:
+ values[0] = sound->VibratoLfo.Delay;
+ break;
+ case AL_VIBRATO_LFO_FREQUENCY_SOFT:
+ values[0] = sound->VibratoLfo.Frequency;
+ break;
+
+ case AL_MOD_ENV_DELAYTIME_SOFT:
+ values[0] = sound->ModEnv.DelayTime;
+ break;
+ case AL_MOD_ENV_ATTACKTIME_SOFT:
+ values[0] = sound->ModEnv.AttackTime;
+ break;
+ case AL_MOD_ENV_HOLDTIME_SOFT:
+ values[0] = sound->ModEnv.HoldTime;
+ break;
+ case AL_MOD_ENV_DECAYTIME_SOFT:
+ values[0] = sound->ModEnv.DecayTime;
+ break;
+ case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
+ values[0] = sound->ModEnv.SustainAttn;
+ break;
+ case AL_MOD_ENV_RELEASETIME_SOFT:
+ values[0] = sound->ModEnv.ReleaseTime;
+ break;
+ case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
+ values[0] = sound->ModEnv.KeyToHoldTime;
+ break;
+ case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
+ values[0] = sound->ModEnv.KeyToDecayTime;
+ break;
+
+ case AL_VOLUME_ENV_DELAYTIME_SOFT:
+ values[0] = sound->VolEnv.DelayTime;
+ break;
+ case AL_VOLUME_ENV_ATTACKTIME_SOFT:
+ values[0] = sound->VolEnv.AttackTime;
+ break;
+ case AL_VOLUME_ENV_HOLDTIME_SOFT:
+ values[0] = sound->VolEnv.HoldTime;
+ break;
+ case AL_VOLUME_ENV_DECAYTIME_SOFT:
+ values[0] = sound->VolEnv.DecayTime;
+ break;
+ case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
+ values[0] = sound->VolEnv.SustainAttn;
+ break;
+ case AL_VOLUME_ENV_RELEASETIME_SOFT:
+ values[0] = sound->VolEnv.ReleaseTime;
+ break;
+ case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
+ values[0] = sound->VolEnv.KeyToHoldTime;
+ break;
+ case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
+ values[0] = sound->VolEnv.KeyToDecayTime;
+ break;
+
+ case AL_KEY_RANGE_SOFT:
+ values[0] = sound->MinKey;
+ values[1] = sound->MaxKey;
+ break;
+
+ case AL_VELOCITY_RANGE_SOFT:
+ values[0] = sound->MinVelocity;
+ values[1] = sound->MaxVelocity;
+ break;
+
+ case AL_ATTENUATION_SOFT:
+ values[0] = sound->Attenuation;
+ break;
+
+ case AL_TUNING_COARSE_SOFT:
+ values[0] = sound->CoarseTuning;
+ break;
+ case AL_TUNING_FINE_SOFT:
+ values[0] = sound->FineTuning;
+ break;
+
+ case AL_LOOP_MODE_SOFT:
+ values[0] = sound->LoopMode;
+ break;
+
+ case AL_TUNING_SCALE_SOFT:
+ values[0] = sound->TuningScale;
+ break;
+
+ case AL_EXCLUSIVE_CLASS_SOFT:
+ values[0] = sound->ExclusiveClass;
+ break;
+
+ case AL_SAMPLE_START_SOFT:
+ values[0] = sound->Start;
+ break;
+
+ case AL_SAMPLE_END_SOFT:
+ values[0] = sound->End;
+ break;
+
+ case AL_SAMPLE_LOOP_START_SOFT:
+ values[0] = sound->LoopStart;
+ break;
+
+ case AL_SAMPLE_LOOP_END_SOFT:
+ values[0] = sound->LoopEnd;
+ break;
+
+ case AL_SAMPLE_RATE_SOFT:
+ values[0] = sound->SampleRate;
+ break;
+
+ case AL_BASE_KEY_SOFT:
+ values[0] = sound->PitchKey;
+ break;
+
+ case AL_KEY_CORRECTION_SOFT:
+ values[0] = sound->PitchCorrection;
+ break;
+
+ case AL_SAMPLE_TYPE_SOFT:
+ values[0] = sound->SampleType;
+ break;
+
+ case AL_FONTSOUND_LINK_SOFT:
+ values[0] = (sound->Link ? sound->Link->id : 0);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *sound;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ ALfontsound_setModStagei(sound, context, stage, param, value);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALfontsound *sound;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(sound=LookupFontsound(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ ALfontsound_getModStagei(sound, context, stage, param, values);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+
+ALfontsound *NewFontsound(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ ALfontsound *sound;
+ ALenum err;
+
+ sound = calloc(1, sizeof(*sound));
+ if(!sound)
+ SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
+ ALfontsound_Construct(sound);
+
+ err = NewThunkEntry(&sound->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->FontsoundMap, sound->id, sound);
+ if(err != AL_NO_ERROR)
+ {
+ ALfontsound_Destruct(sound);
+ memset(sound, 0, sizeof(*sound));
+ free(sound);
+
+ SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
+ }
+
+ return sound;
+}
+
+
+static void ALfontsound_Construct(ALfontsound *self)
+{
+ self->ref = 0;
+
+ self->MinKey = 0;
+ self->MaxKey = 127;
+ self->MinVelocity = 0;
+ self->MaxVelocity = 127;
+
+ self->ModLfoToPitch = 0;
+ self->VibratoLfoToPitch = 0;
+ self->ModEnvToPitch = 0;
+
+ self->FilterCutoff = 13500;
+ self->FilterQ = 0;
+ self->ModLfoToFilterCutoff = 0;
+ self->ModEnvToFilterCutoff = 0;
+ self->ModLfoToVolume = 0;
+
+ self->ChorusSend = 0;
+ self->ReverbSend = 0;
+
+ self->Pan = 0;
+
+ self->ModLfo.Delay = 0;
+ self->ModLfo.Frequency = 0;
+
+ self->VibratoLfo.Delay = 0;
+ self->VibratoLfo.Frequency = 0;
+
+ self->ModEnv.DelayTime = -12000;
+ self->ModEnv.AttackTime = -12000;
+ self->ModEnv.HoldTime = -12000;
+ self->ModEnv.DecayTime = -12000;
+ self->ModEnv.SustainAttn = 0;
+ self->ModEnv.ReleaseTime = -12000;
+ self->ModEnv.KeyToHoldTime = 0;
+ self->ModEnv.KeyToDecayTime = 0;
+
+ self->VolEnv.DelayTime = -12000;
+ self->VolEnv.AttackTime = -12000;
+ self->VolEnv.HoldTime = -12000;
+ self->VolEnv.DecayTime = -12000;
+ self->VolEnv.SustainAttn = 0;
+ self->VolEnv.ReleaseTime = -12000;
+ self->VolEnv.KeyToHoldTime = 0;
+ self->VolEnv.KeyToDecayTime = 0;
+
+ self->Attenuation = 0;
+
+ self->CoarseTuning = 0;
+ self->FineTuning = 0;
+
+ self->LoopMode = AL_NONE;
+
+ self->TuningScale = 100;
+
+ self->ExclusiveClass = 0;
+
+ self->Start = 0;
+ self->End = 0;
+ self->LoopStart = 0;
+ self->LoopEnd = 0;
+ self->SampleRate = 0;
+ self->PitchKey = 0;
+ self->PitchCorrection = 0;
+ self->SampleType = AL_MONO_SOFT;
+ self->Link = NULL;
+
+ InitUIntMap(&self->ModulatorMap, ~0);
+
+ self->id = 0;
+}
+
+void ALfontsound_Destruct(ALfontsound *self)
+{
+ ALsizei i;
+
+ FreeThunkEntry(self->id);
+ self->id = 0;
+
+ if(self->Link)
+ DecrementRef(&self->Link->ref);
+ self->Link = NULL;
+
+ for(i = 0;i < self->ModulatorMap.size;i++)
+ {
+ free(self->ModulatorMap.array[i].value);
+ self->ModulatorMap.array[i].value = NULL;
+ }
+ ResetUIntMap(&self->ModulatorMap);
+}
+
+void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value)
+{
+ ALfontsound *link;
+
+ switch(param)
+ {
+ case AL_MOD_LFO_TO_PITCH_SOFT:
+ self->ModLfoToPitch = value;
+ break;
+
+ case AL_VIBRATO_LFO_TO_PITCH_SOFT:
+ self->VibratoLfoToPitch = value;
+ break;
+
+ case AL_MOD_ENV_TO_PITCH_SOFT:
+ self->ModEnvToPitch = value;
+ break;
+
+ case AL_FILTER_CUTOFF_SOFT:
+ self->FilterCutoff = value;
+ break;
+
+ case AL_FILTER_RESONANCE_SOFT:
+ if(!(value >= 0))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->FilterQ = value;
+ break;
+
+ case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
+ self->ModLfoToFilterCutoff = value;
+ break;
+
+ case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
+ self->ModEnvToFilterCutoff = value;
+ break;
+
+ case AL_MOD_LFO_TO_VOLUME_SOFT:
+ self->ModLfoToVolume = value;
+ break;
+
+ case AL_CHORUS_SEND_SOFT:
+ if(!(value >= 0 && value <= 1000))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->ChorusSend = value;
+ break;
+ case AL_REVERB_SEND_SOFT:
+ if(!(value >= 0 && value <= 1000))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->ReverbSend = value;
+ break;
+
+ case AL_PAN_SOFT:
+ self->Pan = value;
+ break;
+
+ case AL_MOD_LFO_DELAY_SOFT:
+ self->ModLfo.Delay = value;
+ break;
+ case AL_MOD_LFO_FREQUENCY_SOFT:
+ self->ModLfo.Frequency = value;
+ break;
+
+ case AL_VIBRATO_LFO_DELAY_SOFT:
+ self->VibratoLfo.Delay = value;
+ break;
+ case AL_VIBRATO_LFO_FREQUENCY_SOFT:
+ self->VibratoLfo.Frequency = value;
+ break;
+
+ case AL_MOD_ENV_DELAYTIME_SOFT:
+ self->ModEnv.DelayTime = value;
+ break;
+ case AL_MOD_ENV_ATTACKTIME_SOFT:
+ self->ModEnv.AttackTime = value;
+ break;
+ case AL_MOD_ENV_HOLDTIME_SOFT:
+ self->ModEnv.HoldTime = value;
+ break;
+ case AL_MOD_ENV_DECAYTIME_SOFT:
+ self->ModEnv.DecayTime = value;
+ break;
+ case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
+ self->ModEnv.SustainAttn = value;
+ break;
+ case AL_MOD_ENV_RELEASETIME_SOFT:
+ self->ModEnv.ReleaseTime = value;
+ break;
+ case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
+ self->ModEnv.KeyToHoldTime = value;
+ break;
+ case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
+ self->ModEnv.KeyToDecayTime = value;
+ break;
+
+ case AL_VOLUME_ENV_DELAYTIME_SOFT:
+ self->VolEnv.DelayTime = value;
+ break;
+ case AL_VOLUME_ENV_ATTACKTIME_SOFT:
+ self->VolEnv.AttackTime = value;
+ break;
+ case AL_VOLUME_ENV_HOLDTIME_SOFT:
+ self->VolEnv.HoldTime = value;
+ break;
+ case AL_VOLUME_ENV_DECAYTIME_SOFT:
+ self->VolEnv.DecayTime = value;
+ break;
+ case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
+ self->VolEnv.SustainAttn = value;
+ break;
+ case AL_VOLUME_ENV_RELEASETIME_SOFT:
+ self->VolEnv.ReleaseTime = value;
+ break;
+ case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
+ self->VolEnv.KeyToHoldTime = value;
+ break;
+ case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
+ self->VolEnv.KeyToDecayTime = value;
+ break;
+
+ case AL_ATTENUATION_SOFT:
+ if(!(value >= 0))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->Attenuation = value;
+ break;
+
+ case AL_TUNING_COARSE_SOFT:
+ self->CoarseTuning = value;
+ break;
+ case AL_TUNING_FINE_SOFT:
+ self->FineTuning = value;
+ break;
+
+ case AL_LOOP_MODE_SOFT:
+ if(!(value == AL_NONE || value == AL_LOOP_CONTINUOUS_SOFT ||
+ value == AL_LOOP_UNTIL_RELEASE_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->LoopMode = value;
+ break;
+
+ case AL_TUNING_SCALE_SOFT:
+ self->TuningScale = value;
+ break;
+
+ case AL_EXCLUSIVE_CLASS_SOFT:
+ self->ExclusiveClass = value;
+ break;
+
+ case AL_SAMPLE_START_SOFT:
+ self->Start = value;
+ break;
+
+ case AL_SAMPLE_END_SOFT:
+ self->End = value;
+ break;
+
+ case AL_SAMPLE_LOOP_START_SOFT:
+ self->LoopStart = value;
+ break;
+
+ case AL_SAMPLE_LOOP_END_SOFT:
+ self->LoopEnd = value;
+ break;
+
+ case AL_SAMPLE_RATE_SOFT:
+ if(!(value > 0))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->SampleRate = value;
+ break;
+
+ case AL_BASE_KEY_SOFT:
+ if(!((value >= 0 && value <= 127) || value == 255))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->PitchKey = value;
+ break;
+
+ case AL_KEY_CORRECTION_SOFT:
+ if(!(value >= -99 && value <= 99))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->PitchCorrection = value;
+ break;
+
+ case AL_SAMPLE_TYPE_SOFT:
+ if(!(value == AL_MONO_SOFT || value == AL_RIGHT_SOFT || value == AL_LEFT_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ self->SampleType = value;
+ break;
+
+ case AL_FONTSOUND_LINK_SOFT:
+ if(!value)
+ link = NULL;
+ else
+ {
+ link = LookupFontsound(context->Device, value);
+ if(!link)
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ }
+ if(link) IncrementRef(&link->ref);
+ link = ExchangePtr((XchgPtr*)&self->Link, link);
+ if(link) DecrementRef(&link->ref);
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+
+static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage)
+{
+ ALsfmodulator *ret = LookupModulator(self, stage);
+ if(!ret)
+ {
+ static const ALsfmodulator moddef = {
+ { { AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT },
+ { AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT }
+ },
+ 0,
+ AL_LINEAR_SOFT,
+ AL_NONE
+ };
+ ret = malloc(sizeof(*ret));
+ *ret = moddef;
+ InsertUIntMapEntry(&self->ModulatorMap, stage, ret);
+ }
+ return ret;
+}
+
+void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value)
+{
+ ALint srcidx = 0;
+
+ if(self->ref != 0)
+ SET_ERROR_AND_RETURN(context, AL_INVALID_OPERATION);
+ switch(param)
+ {
+ case AL_SOURCE1_INPUT_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_INPUT_SOFT:
+ if(!(value == AL_ONE_SOFT || value == AL_NOTEON_VELOCITY_SOFT ||
+ value == AL_NOTEON_KEY_SOFT || value == AL_KEYPRESSURE_SOFT ||
+ value == AL_CHANNELPRESSURE_SOFT || value == AL_PITCHBEND_SOFT ||
+ value == AL_PITCHBEND_SENSITIVITY_SOFT ||
+ (value > 0 && value < 120 && !(value == 6 || (value >= 32 && value <= 63) ||
+ (value >= 98 && value <= 101))
+ )
+ ))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ ALfontsound_getModStage(self, stage)->Source[srcidx].Input = value;
+ break;
+
+ case AL_SOURCE1_TYPE_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_TYPE_SOFT:
+ if(!(value == AL_UNORM_SOFT || value == AL_UNORM_REV_SOFT ||
+ value == AL_SNORM_SOFT || value == AL_SNORM_REV_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ ALfontsound_getModStage(self, stage)->Source[srcidx].Type = value;
+ break;
+
+ case AL_SOURCE1_FORM_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_FORM_SOFT:
+ if(!(value == AL_LINEAR_SOFT || value == AL_CONCAVE_SOFT ||
+ value == AL_CONVEX_SOFT || value == AL_SWITCH_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ ALfontsound_getModStage(self, stage)->Source[srcidx].Form = value;
+ break;
+
+ case AL_AMOUNT_SOFT:
+ ALfontsound_getModStage(self, stage)->Amount = value;
+ break;
+
+ case AL_TRANSFORM_OP_SOFT:
+ if(!(value == AL_LINEAR_SOFT || value == AL_ABSOLUTE_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ ALfontsound_getModStage(self, stage)->TransformOp = value;
+ break;
+
+ case AL_DESTINATION_SOFT:
+ if(!(value == AL_MOD_LFO_TO_PITCH_SOFT || value == AL_VIBRATO_LFO_TO_PITCH_SOFT ||
+ value == AL_MOD_ENV_TO_PITCH_SOFT || value == AL_FILTER_CUTOFF_SOFT ||
+ value == AL_FILTER_RESONANCE_SOFT || value == AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT ||
+ value == AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT || value == AL_MOD_LFO_TO_VOLUME_SOFT ||
+ value == AL_CHORUS_SEND_SOFT || value == AL_REVERB_SEND_SOFT || value == AL_PAN_SOFT ||
+ value == AL_MOD_LFO_DELAY_SOFT || value == AL_MOD_LFO_FREQUENCY_SOFT ||
+ value == AL_VIBRATO_LFO_DELAY_SOFT || value == AL_VIBRATO_LFO_FREQUENCY_SOFT ||
+ value == AL_MOD_ENV_DELAYTIME_SOFT || value == AL_MOD_ENV_ATTACKTIME_SOFT ||
+ value == AL_MOD_ENV_HOLDTIME_SOFT || value == AL_MOD_ENV_DECAYTIME_SOFT ||
+ value == AL_MOD_ENV_SUSTAINVOLUME_SOFT || value == AL_MOD_ENV_RELEASETIME_SOFT ||
+ value == AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT ||
+ value == AL_VOLUME_ENV_DELAYTIME_SOFT || value == AL_VOLUME_ENV_ATTACKTIME_SOFT ||
+ value == AL_VOLUME_ENV_HOLDTIME_SOFT || value == AL_VOLUME_ENV_DECAYTIME_SOFT ||
+ value == AL_VOLUME_ENV_SUSTAINVOLUME_SOFT || value == AL_VOLUME_ENV_RELEASETIME_SOFT ||
+ value == AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT ||
+ value == AL_ATTENUATION_SOFT || value == AL_TUNING_COARSE_SOFT ||
+ value == AL_TUNING_FINE_SOFT || value == AL_TUNING_SCALE_SOFT))
+ SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+ ALfontsound_getModStage(self, stage)->Dest = value;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+
+static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values)
+{
+ ALsfmodulator *mod = LookupModulator(self, stage);
+ ALint srcidx = 0;
+
+ switch(param)
+ {
+ case AL_SOURCE1_INPUT_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_INPUT_SOFT:
+ values[0] = mod ? mod->Source[srcidx].Input : AL_ONE_SOFT;
+ break;
+
+ case AL_SOURCE1_TYPE_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_TYPE_SOFT:
+ values[0] = mod ? mod->Source[srcidx].Type : AL_UNORM_SOFT;
+ break;
+
+ case AL_SOURCE1_FORM_SOFT:
+ srcidx++;
+ /* fall-through */
+ case AL_SOURCE0_FORM_SOFT:
+ values[0] = mod ? mod->Source[srcidx].Form : AL_LINEAR_SOFT;
+ break;
+
+ case AL_AMOUNT_SOFT:
+ values[0] = mod ? mod->Amount : 0;
+ break;
+
+ case AL_TRANSFORM_OP_SOFT:
+ values[0] = mod ? mod->TransformOp : AL_LINEAR_SOFT;
+ break;
+
+ case AL_DESTINATION_SOFT:
+ values[0] = mod ? mod->Dest : AL_NONE;
+ break;
+
+ default:
+ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+ }
+}
+
+
+/* ReleaseALFontsounds
+ *
+ * Called to destroy any fontsounds that still exist on the device
+ */
+void ReleaseALFontsounds(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->FontsoundMap.size;i++)
+ {
+ ALfontsound *temp = device->FontsoundMap.array[i].value;
+ device->FontsoundMap.array[i].value = NULL;
+
+ ALfontsound_Destruct(temp);
+
+ memset(temp, 0, sizeof(*temp));
+ free(temp);
+ }
+}
diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c
index 682acbb5..87cd3c61 100644
--- a/OpenAL32/alListener.c
+++ b/OpenAL32/alListener.c
@@ -28,445 +28,419 @@
AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(param)
{
- switch(param)
- {
- case AL_GAIN:
- CHECK_VALUE(Context, value >= 0.0f && isfinite(value));
+ case AL_GAIN:
+ if(!(value >= 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Context->Listener->Gain = value;
- Context->UpdateSources = AL_TRUE;
- break;
+ context->Listener->Gain = value;
+ context->UpdateSources = AL_TRUE;
+ break;
- case AL_METERS_PER_UNIT:
- CHECK_VALUE(Context, value >= 0.0f && isfinite(value));
+ case AL_METERS_PER_UNIT:
+ if(!(value >= 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Context->Listener->MetersPerUnit = value;
- Context->UpdateSources = AL_TRUE;
- break;
+ context->Listener->MetersPerUnit = value;
+ context->UpdateSources = AL_TRUE;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(param)
{
- switch(param)
- {
- case AL_POSITION:
- CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
-
- LockContext(Context);
- Context->Listener->Position[0] = value1;
- Context->Listener->Position[1] = value2;
- Context->Listener->Position[2] = value3;
- Context->UpdateSources = AL_TRUE;
- UnlockContext(Context);
- break;
-
- case AL_VELOCITY:
- CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3));
-
- LockContext(Context);
- Context->Listener->Velocity[0] = value1;
- Context->Listener->Velocity[1] = value2;
- Context->Listener->Velocity[2] = value3;
- Context->UpdateSources = AL_TRUE;
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_POSITION:
+ if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ LockContext(context);
+ context->Listener->Position[0] = value1;
+ context->Listener->Position[1] = value2;
+ context->Listener->Position[2] = value3;
+ context->UpdateSources = AL_TRUE;
+ UnlockContext(context);
+ break;
+
+ case AL_VELOCITY:
+ if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ LockContext(context);
+ context->Listener->Velocity[0] = value1;
+ context->Listener->Velocity[1] = value2;
+ context->Listener->Velocity[2] = value3;
+ context->UpdateSources = AL_TRUE;
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
if(values)
{
switch(param)
{
- case AL_GAIN:
- case AL_METERS_PER_UNIT:
- alListenerf(param, values[0]);
- return;
-
- case AL_POSITION:
- case AL_VELOCITY:
- alListener3f(param, values[0], values[1], values[2]);
- return;
+ case AL_GAIN:
+ case AL_METERS_PER_UNIT:
+ alListenerf(param, values[0]);
+ return;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alListener3f(param, values[0], values[1], values[2]);
+ return;
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, values);
- switch(param)
- {
- case AL_ORIENTATION:
- CHECK_VALUE(Context, isfinite(values[0]) && isfinite(values[1]) &&
- isfinite(values[2]) && isfinite(values[3]) &&
- isfinite(values[4]) && isfinite(values[5]));
-
- LockContext(Context);
- /* AT then UP */
- Context->Listener->Forward[0] = values[0];
- Context->Listener->Forward[1] = values[1];
- Context->Listener->Forward[2] = values[2];
- Context->Listener->Up[0] = values[3];
- Context->Listener->Up[1] = values[4];
- Context->Listener->Up[2] = values[5];
- Context->UpdateSources = AL_TRUE;
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_ORIENTATION:
+ if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
+ isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ LockContext(context);
+ /* AT then UP */
+ context->Listener->Forward[0] = values[0];
+ context->Listener->Forward[1] = values[1];
+ context->Listener->Forward[2] = values[2];
+ context->Listener->Up[0] = values[3];
+ context->Listener->Up[1] = values[4];
+ context->Listener->Up[2] = values[5];
+ context->UpdateSources = AL_TRUE;
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
-AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint value)
+AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
{
- ALCcontext *Context;
-
- (void)value;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(param)
{
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_POSITION:
- case AL_VELOCITY:
- alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
- return;
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(param)
{
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
if(values)
{
ALfloat fvals[6];
switch(param)
{
- case AL_POSITION:
- case AL_VELOCITY:
- alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
- return;
-
- case AL_ORIENTATION:
- fvals[0] = (ALfloat)values[0];
- fvals[1] = (ALfloat)values[1];
- fvals[2] = (ALfloat)values[2];
- fvals[3] = (ALfloat)values[3];
- fvals[4] = (ALfloat)values[4];
- fvals[5] = (ALfloat)values[5];
- alListenerfv(param, fvals);
- return;
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
+ return;
+
+ case AL_ORIENTATION:
+ fvals[0] = (ALfloat)values[0];
+ fvals[1] = (ALfloat)values[1];
+ fvals[2] = (ALfloat)values[2];
+ fvals[3] = (ALfloat)values[3];
+ fvals[4] = (ALfloat)values[4];
+ fvals[5] = (ALfloat)values[5];
+ alListenerfv(param, fvals);
+ return;
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, values);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(value))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, value);
- switch(param)
- {
- case AL_GAIN:
- *value = Context->Listener->Gain;
- break;
+ case AL_GAIN:
+ *value = context->Listener->Gain;
+ break;
- case AL_METERS_PER_UNIT:
- *value = Context->Listener->MetersPerUnit;
- break;
+ case AL_METERS_PER_UNIT:
+ *value = context->Listener->MetersPerUnit;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(value1 && value2 && value3))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, value1 && value2 && value3);
- switch(param)
- {
- case AL_POSITION:
- LockContext(Context);
- *value1 = Context->Listener->Position[0];
- *value2 = Context->Listener->Position[1];
- *value3 = Context->Listener->Position[2];
- UnlockContext(Context);
- break;
-
- case AL_VELOCITY:
- LockContext(Context);
- *value1 = Context->Listener->Velocity[0];
- *value2 = Context->Listener->Velocity[1];
- *value3 = Context->Listener->Velocity[2];
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_POSITION:
+ LockContext(context);
+ *value1 = context->Listener->Position[0];
+ *value2 = context->Listener->Position[1];
+ *value3 = context->Listener->Position[2];
+ UnlockContext(context);
+ break;
+
+ case AL_VELOCITY:
+ LockContext(context);
+ *value1 = context->Listener->Velocity[0];
+ *value2 = context->Listener->Velocity[1];
+ *value3 = context->Listener->Velocity[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_GAIN:
- case AL_METERS_PER_UNIT:
- alGetListenerf(param, values);
- return;
-
- case AL_POSITION:
- case AL_VELOCITY:
- alGetListener3f(param, values+0, values+1, values+2);
- return;
+ case AL_GAIN:
+ case AL_METERS_PER_UNIT:
+ alGetListenerf(param, values);
+ return;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alGetListener3f(param, values+0, values+1, values+2);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, values);
- switch(param)
- {
- case AL_ORIENTATION:
- LockContext(Context);
- // AT then UP
- values[0] = Context->Listener->Forward[0];
- values[1] = Context->Listener->Forward[1];
- values[2] = Context->Listener->Forward[2];
- values[3] = Context->Listener->Up[0];
- values[4] = Context->Listener->Up[1];
- values[5] = Context->Listener->Up[2];
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_ORIENTATION:
+ LockContext(context);
+ // AT then UP
+ values[0] = context->Listener->Forward[0];
+ values[1] = context->Listener->Forward[1];
+ values[2] = context->Listener->Forward[2];
+ values[3] = context->Listener->Up[0];
+ values[4] = context->Listener->Up[1];
+ values[5] = context->Listener->Up[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(value))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, value);
- switch(param)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(value1 && value2 && value3))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch (param)
{
- CHECK_VALUE(Context, value1 && value2 && value3);
- switch (param)
- {
- case AL_POSITION:
- LockContext(Context);
- *value1 = (ALint)Context->Listener->Position[0];
- *value2 = (ALint)Context->Listener->Position[1];
- *value3 = (ALint)Context->Listener->Position[2];
- UnlockContext(Context);
- break;
-
- case AL_VELOCITY:
- LockContext(Context);
- *value1 = (ALint)Context->Listener->Velocity[0];
- *value2 = (ALint)Context->Listener->Velocity[1];
- *value3 = (ALint)Context->Listener->Velocity[2];
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_POSITION:
+ LockContext(context);
+ *value1 = (ALint)context->Listener->Position[0];
+ *value2 = (ALint)context->Listener->Position[1];
+ *value3 = (ALint)context->Listener->Position[2];
+ UnlockContext(context);
+ break;
+
+ case AL_VELOCITY:
+ LockContext(context);
+ *value1 = (ALint)context->Listener->Velocity[0];
+ *value2 = (ALint)context->Listener->Velocity[1];
+ *value3 = (ALint)context->Listener->Velocity[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
{
- ALCcontext *Context;
+ ALCcontext *context;
switch(param)
{
- case AL_POSITION:
- case AL_VELOCITY:
- alGetListener3i(param, values+0, values+1, values+2);
- return;
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alGetListener3i(param, values+0, values+1, values+2);
+ return;
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(param)
{
- CHECK_VALUE(Context, values);
- switch(param)
- {
- case AL_ORIENTATION:
- LockContext(Context);
- // AT then UP
- values[0] = (ALint)Context->Listener->Forward[0];
- values[1] = (ALint)Context->Listener->Forward[1];
- values[2] = (ALint)Context->Listener->Forward[2];
- values[3] = (ALint)Context->Listener->Up[0];
- values[4] = (ALint)Context->Listener->Up[1];
- values[5] = (ALint)Context->Listener->Up[2];
- UnlockContext(Context);
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_ORIENTATION:
+ LockContext(context);
+ // AT then UP
+ values[0] = (ALint)context->Listener->Forward[0];
+ values[1] = (ALint)context->Listener->Forward[1];
+ values[2] = (ALint)context->Listener->Forward[2];
+ values[3] = (ALint)context->Listener->Up[0];
+ values[4] = (ALint)context->Listener->Up[1];
+ values[5] = (ALint)context->Listener->Up[2];
+ UnlockContext(context);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
diff --git a/OpenAL32/alMidi.c b/OpenAL32/alMidi.c
new file mode 100644
index 00000000..0679b64c
--- /dev/null
+++ b/OpenAL32/alMidi.c
@@ -0,0 +1,221 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "alMain.h"
+#include "alMidi.h"
+#include "alError.h"
+#include "alThunk.h"
+#include "evtqueue.h"
+#include "rwlock.h"
+#include "alu.h"
+
+#include "midi/base.h"
+
+
+MidiSynth *SynthCreate(ALCdevice *device)
+{
+ MidiSynth *synth = FSynth_create(device);
+ if(!synth) synth = DSynth_create(device);
+ return synth;
+}
+
+
+AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id)
+{
+ alMidiSoundfontvSOFT(1, &id);
+}
+
+AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ MidiSynth *synth;
+ ALenum err;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(count < 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ synth = device->Synth;
+
+ WriteLock(&synth->Lock);
+ if(synth->State == AL_PLAYING || synth->State == AL_PAUSED)
+ alSetError(context, AL_INVALID_OPERATION);
+ else
+ {
+ err = V(synth,selectSoundfonts)(context, count, ids);
+ if(err != AL_NO_ERROR)
+ alSetError(context, err);
+ }
+ WriteUnlock(&synth->Lock);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+
+AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALenum err;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(event == AL_NOTEOFF_SOFT || event == AL_NOTEON_SOFT ||
+ event == AL_KEYPRESSURE_SOFT || event == AL_CONTROLLERCHANGE_SOFT ||
+ event == AL_PROGRAMCHANGE_SOFT || event == AL_CHANNELPRESSURE_SOFT ||
+ event == AL_PITCHBEND_SOFT))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ if(!(channel >= 0 && channel <= 15))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(!(param1 >= 0 && param1 <= 127))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(!(param2 >= 0 && param2 <= 127))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ ALCdevice_Lock(device);
+ err = MidiSynth_insertEvent(device->Synth, time, event|channel, param1, param2);
+ ALCdevice_Unlock(device);
+ if(err != AL_NO_ERROR)
+ alSetError(context, err);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALenum err;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!data || size < 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < size;i++)
+ {
+ if((data[i]&0x80))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
+
+ device = context->Device;
+ ALCdevice_Lock(device);
+ err = MidiSynth_insertSysExEvent(device->Synth, time, data, size);
+ ALCdevice_Unlock(device);
+ if(err != AL_NO_ERROR)
+ alSetError(context, err);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alMidiPlaySOFT(void)
+{
+ ALCcontext *context;
+ MidiSynth *synth;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ synth = context->Device->Synth;
+ WriteLock(&synth->Lock);
+ V(synth,setState)(AL_PLAYING);
+ WriteUnlock(&synth->Lock);
+
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alMidiPauseSOFT(void)
+{
+ ALCcontext *context;
+ MidiSynth *synth;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ synth = context->Device->Synth;
+ WriteLock(&synth->Lock);
+ V(synth,setState)(AL_PAUSED);
+ WriteUnlock(&synth->Lock);
+
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alMidiStopSOFT(void)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ MidiSynth *synth;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ synth = device->Synth;
+
+ WriteLock(&synth->Lock);
+ V(synth,setState)(AL_STOPPED);
+
+ ALCdevice_Lock(device);
+ V0(synth,stop)();
+ ALCdevice_Unlock(device);
+ WriteUnlock(&synth->Lock);
+
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alMidiResetSOFT(void)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ MidiSynth *synth;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ synth = device->Synth;
+
+ WriteLock(&synth->Lock);
+ V(synth,setState)(AL_INITIAL);
+
+ ALCdevice_Lock(device);
+ V0(synth,reset)();
+ ALCdevice_Unlock(device);
+ WriteUnlock(&synth->Lock);
+
+ ALCcontext_DecRef(context);
+}
+
+
+AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(value >= 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ V(device->Synth,setGain)(value);
+
+done:
+ ALCcontext_DecRef(context);
+}
diff --git a/OpenAL32/alPreset.c b/OpenAL32/alPreset.c
new file mode 100644
index 00000000..d34772a4
--- /dev/null
+++ b/OpenAL32/alPreset.c
@@ -0,0 +1,340 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "alMain.h"
+#include "alMidi.h"
+#include "alError.h"
+#include "alThunk.h"
+
+#include "midi/base.h"
+
+
+extern inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id);
+extern inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id);
+
+static void ALsfpreset_Construct(ALsfpreset *self);
+void ALsfpreset_Destruct(ALsfpreset *self);
+
+
+AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids)
+{
+ ALCcontext *context;
+ ALsizei cur = 0;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ for(cur = 0;cur < n;cur++)
+ {
+ ALsfpreset *preset = NewPreset(context);
+ if(!preset)
+ {
+ alDeletePresetsSOFT(cur, ids);
+ break;
+ }
+
+ ids[cur] = preset->id;
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsfpreset *preset;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ /* Check for valid ID */
+ if((preset=LookupPreset(device, ids[i])) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(preset->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ if((preset=LookupPreset(device, ids[i])) == NULL)
+ continue;
+ DeletePreset(preset, device);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id)
+{
+ ALCcontext *context;
+ ALboolean ret;
+
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
+
+ ret = LookupPreset(context->Device, id) ? AL_TRUE : AL_FALSE;
+
+ ALCcontext_DecRef(context);
+
+ return ret;
+}
+
+AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsfpreset *preset;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((preset=LookupPreset(device, id)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(preset->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ switch(param)
+ {
+ case AL_MIDI_PRESET_SOFT:
+ if(!(value >= 0 && value <= 127))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ preset->Preset = value;
+ break;
+
+ case AL_MIDI_BANK_SOFT:
+ if(!(value >= 0 && value <= 128))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ preset->Bank = value;
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsfpreset *preset;
+
+ switch(param)
+ {
+ case AL_MIDI_PRESET_SOFT:
+ case AL_MIDI_BANK_SOFT:
+ alPresetiSOFT(id, param, values[0]);
+ return;
+ }
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((preset=LookupPreset(device, id)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(preset->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ switch(param)
+ {
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsfpreset *preset;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if((preset=LookupPreset(device, id)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
+ {
+ case AL_MIDI_PRESET_SOFT:
+ values[0] = preset->Preset;
+ break;
+
+ case AL_MIDI_BANK_SOFT:
+ values[0] = preset->Bank;
+ break;
+
+ case AL_FONTSOUNDS_SIZE_SOFT:
+ values[0] = preset->NumSounds;
+ break;
+
+ case AL_FONTSOUNDS_SOFT:
+ for(i = 0;i < preset->NumSounds;i++)
+ values[i] = preset->Sounds[i]->id;
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsfpreset *preset;
+ ALfontsound **sounds;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(!(preset=LookupPreset(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(count < 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ if(preset->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+
+ if(count == 0)
+ sounds = NULL;
+ else
+ {
+ sounds = calloc(count, sizeof(sounds[0]));
+ if(!sounds)
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+
+ for(i = 0;i < count;i++)
+ {
+ if(!(sounds[i]=LookupFontsound(device, fsids[i])))
+ {
+ free(sounds);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
+ }
+ }
+
+ for(i = 0;i < count;i++)
+ IncrementRef(&sounds[i]->ref);
+
+ sounds = ExchangePtr((XchgPtr*)&preset->Sounds, sounds);
+ count = ExchangeInt(&preset->NumSounds, count);
+
+ for(i = 0;i < count;i++)
+ DecrementRef(&sounds[i]->ref);
+ free(sounds);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+
+ALsfpreset *NewPreset(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ ALsfpreset *preset;
+ ALenum err;
+
+ preset = calloc(1, sizeof(*preset));
+ if(!preset)
+ SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
+ ALsfpreset_Construct(preset);
+
+ err = NewThunkEntry(&preset->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->PresetMap, preset->id, preset);
+ if(err != AL_NO_ERROR)
+ {
+ ALsfpreset_Destruct(preset);
+ memset(preset, 0, sizeof(*preset));
+ free(preset);
+
+ SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
+ }
+
+ return preset;
+}
+
+void DeletePreset(ALsfpreset *preset, ALCdevice *device)
+{
+ RemovePreset(device, preset->id);
+
+ ALsfpreset_Destruct(preset);
+ memset(preset, 0, sizeof(*preset));
+ free(preset);
+}
+
+
+static void ALsfpreset_Construct(ALsfpreset *self)
+{
+ self->ref = 0;
+
+ self->Preset = 0;
+ self->Bank = 0;
+
+ self->Sounds = NULL;
+ self->NumSounds = 0;
+
+ self->id = 0;
+}
+
+void ALsfpreset_Destruct(ALsfpreset *self)
+{
+ ALsizei i;
+
+ FreeThunkEntry(self->id);
+ self->id = 0;
+
+ for(i = 0;i < self->NumSounds;i++)
+ DecrementRef(&self->Sounds[i]->ref);
+ free(self->Sounds);
+ self->Sounds = NULL;
+ self->NumSounds = 0;
+}
+
+
+/* ReleaseALPresets
+ *
+ * Called to destroy any presets that still exist on the device
+ */
+void ReleaseALPresets(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->PresetMap.size;i++)
+ {
+ ALsfpreset *temp = device->PresetMap.array[i].value;
+ device->PresetMap.array[i].value = NULL;
+
+ ALsfpreset_Destruct(temp);
+
+ memset(temp, 0, sizeof(*temp));
+ free(temp);
+ }
+}
diff --git a/OpenAL32/alSoundfont.c b/OpenAL32/alSoundfont.c
new file mode 100644
index 00000000..355c5b41
--- /dev/null
+++ b/OpenAL32/alSoundfont.c
@@ -0,0 +1,563 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "alMain.h"
+#include "alMidi.h"
+#include "alThunk.h"
+#include "alError.h"
+
+#include "midi/base.h"
+
+
+extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id);
+extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id);
+
+void ALsoundfont_Construct(ALsoundfont *self);
+void ALsoundfont_Destruct(ALsoundfont *self);
+void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
+ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
+static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr);
+
+
+AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsizei cur = 0;
+ ALenum err;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ for(cur = 0;cur < n;cur++)
+ {
+ ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont));
+ if(!sfont)
+ {
+ alDeleteSoundfontsSOFT(cur, ids);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ }
+ ALsoundfont_Construct(sfont);
+
+ err = NewThunkEntry(&sfont->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont);
+ if(err != AL_NO_ERROR)
+ {
+ ALsoundfont_Destruct(sfont);
+ memset(sfont, 0, sizeof(ALsoundfont));
+ free(sfont);
+
+ alDeleteSoundfontsSOFT(cur, ids);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ ids[cur] = sfont->id;
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ device = context->Device;
+ for(i = 0;i < n;i++)
+ {
+ /* Check for valid soundfont ID */
+ if(ids[i] == 0)
+ {
+ if(!(sfont=device->DefaultSfont))
+ continue;
+ }
+ else if((sfont=LookupSfont(device, ids[i])) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(sfont->Mapped != AL_FALSE || sfont->ref != 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ if(ids[i] == 0)
+ {
+ MidiSynth *synth = device->Synth;
+ WriteLock(&synth->Lock);
+ if(device->DefaultSfont != NULL)
+ ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
+ device->DefaultSfont = NULL;
+ WriteUnlock(&synth->Lock);
+ continue;
+ }
+ else if((sfont=RemoveSfont(device, ids[i])) == NULL)
+ continue;
+
+ ALsoundfont_Destruct(sfont);
+
+ memset(sfont, 0, sizeof(*sfont));
+ free(sfont);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
+{
+ ALCcontext *context;
+ ALboolean ret;
+
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
+
+ ret = ((!id || LookupSfont(context->Device, id)) ?
+ AL_TRUE : AL_FALSE);
+
+ ALCcontext_DecRef(context);
+
+ return ret;
+}
+
+AL_API ALvoid AL_APIENTRY alSoundfontSamplesSOFT(ALuint id, ALenum type, ALsizei count, const ALvoid *samples)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ void *ptr;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(type != AL_SHORT_SOFT)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(count <= 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ WriteLock(&sfont->Lock);
+ if(sfont->ref != 0)
+ alSetError(context, AL_INVALID_OPERATION);
+ else if(sfont->Mapped)
+ alSetError(context, AL_INVALID_OPERATION);
+ else if(!(ptr=realloc(sfont->Samples, count * sizeof(ALshort))))
+ alSetError(context, AL_OUT_OF_MEMORY);
+ else
+ {
+ sfont->Samples = ptr;
+ sfont->NumSamples = count;
+ if(samples != NULL)
+ memcpy(sfont->Samples, samples, count * sizeof(ALshort));
+ }
+ WriteUnlock(&sfont->Lock);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetSoundfontSamplesSOFT(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ sfont = ALsoundfont_getDefSoundfont(context);
+ else if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(type != AL_SHORT_SOFT)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(offset < 0 || count <= 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ ReadLock(&sfont->Lock);
+ if(offset >= sfont->NumSamples || count > (sfont->NumSamples-offset))
+ alSetError(context, AL_INVALID_VALUE);
+ else if(sfont->Mapped)
+ alSetError(context, AL_INVALID_OPERATION);
+ else
+ {
+ /* TODO: Allow conversion. */
+ memcpy(samples, sfont->Samples + offset*sizeof(ALshort), count * sizeof(ALshort));
+ }
+ ReadUnlock(&sfont->Lock);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint id, ALsizei offset, ALsizei length)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ ALvoid *ptr = NULL;
+
+ context = GetContextRef();
+ if(!context) return NULL;
+
+ device = context->Device;
+ if(id == 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(offset < 0 || (ALuint)offset > sfont->NumSamples*sizeof(ALshort))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if(length <= 0 || (ALuint)length > (sfont->NumSamples*sizeof(ALshort) - offset))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ ReadLock(&sfont->Lock);
+ if(sfont->ref != 0)
+ alSetError(context, AL_INVALID_OPERATION);
+ else if(ExchangeInt(&sfont->Mapped, AL_TRUE) == AL_TRUE)
+ alSetError(context, AL_INVALID_OPERATION);
+ else
+ ptr = (ALbyte*)sfont->Samples + offset;
+ ReadUnlock(&sfont->Lock);
+
+done:
+ ALCcontext_DecRef(context);
+
+ return ptr;
+}
+
+AL_API ALvoid AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint id)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(ExchangeInt(&sfont->Mapped, AL_FALSE) == AL_FALSE)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ sfont = ALsoundfont_getDefSoundfont(context);
+ else if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ switch(param)
+ {
+ case AL_PRESETS_SIZE_SOFT:
+ values[0] = sfont->NumPresets;
+ break;
+
+ case AL_PRESETS_SOFT:
+ for(i = 0;i < sfont->NumPresets;i++)
+ values[i] = sfont->Presets[i]->id;
+ break;
+
+ case AL_SAMPLE_LENGTH_SOFT:
+ values[0] = sfont->NumSamples;
+ break;
+
+ case AL_FORMAT_TYPE_SOFT:
+ values[0] = AL_SHORT_SOFT;
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ ALsfpreset **presets;
+ ALsizei i;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ if(count < 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ WriteLock(&sfont->Lock);
+ if(sfont->ref != 0)
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+
+ if(count == 0)
+ presets = NULL;
+ else
+ {
+ presets = calloc(count, sizeof(presets[0]));
+ if(!presets)
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ }
+
+ for(i = 0;i < count;i++)
+ {
+ if(!(presets[i]=LookupPreset(device, pids[i])))
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
+ }
+ }
+
+ for(i = 0;i < count;i++)
+ IncrementRef(&presets[i]->ref);
+
+ presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets);
+ count = ExchangeInt(&sfont->NumPresets, count);
+ WriteUnlock(&sfont->Lock);
+
+ for(i = 0;i < count;i++)
+ DecrementRef(&presets[i]->ref);
+ free(presets);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+
+AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user)
+{
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsoundfont *sfont;
+ Reader reader;
+
+ context = GetContextRef();
+ if(!context) return;
+
+ device = context->Device;
+ if(id == 0)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ if(!(sfont=LookupSfont(device, id)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+
+ WriteLock(&sfont->Lock);
+ if(sfont->ref != 0)
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+ if(sfont->Mapped)
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+ if(sfont->NumPresets > 0)
+ {
+ WriteUnlock(&sfont->Lock);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
+
+ reader.cb = cb;
+ reader.ptr = user;
+ reader.error = 0;
+ loadSf2(&reader, sfont, context);
+ WriteUnlock(&sfont->Lock);
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+
+void ALsoundfont_Construct(ALsoundfont *self)
+{
+ self->ref = 0;
+
+ self->Presets = NULL;
+ self->NumPresets = 0;
+
+ self->Samples = NULL;
+ self->NumSamples = 0;
+
+ RWLockInit(&self->Lock);
+ self->Mapped = AL_FALSE;
+
+ self->id = 0;
+}
+
+void ALsoundfont_Destruct(ALsoundfont *self)
+{
+ ALsizei i;
+
+ FreeThunkEntry(self->id);
+ self->id = 0;
+
+ for(i = 0;i < self->NumPresets;i++)
+ {
+ DecrementRef(&self->Presets[i]->ref);
+ self->Presets[i] = NULL;
+ }
+ free(self->Presets);
+ self->Presets = NULL;
+ self->NumPresets = 0;
+
+ free(self->Samples);
+ self->Samples = NULL;
+ self->NumSamples = 0;
+}
+
+ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ const char *fname;
+
+ if(device->DefaultSfont)
+ return device->DefaultSfont;
+
+ device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0]));
+ ALsoundfont_Construct(device->DefaultSfont);
+
+ fname = getenv("ALSOFT_SOUNDFONT");
+ if((fname && fname[0]) || ConfigValueStr("midi", "soundfont", &fname))
+ {
+ FILE *f;
+
+ f = fopen(fname, "rb");
+ if(f == NULL)
+ ERR("Failed to open %s\n", fname);
+ else
+ {
+ Reader reader;
+ reader.cb = ALsoundfont_read;
+ reader.ptr = f;
+ reader.error = 0;
+ TRACE("Loading %s\n", fname);
+ loadSf2(&reader, device->DefaultSfont, context);
+ fclose(f);
+ }
+ }
+
+ return device->DefaultSfont;
+}
+
+void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
+{
+ ALsfpreset **presets;
+ ALsizei num_presets;
+ ALsizei i;
+
+ presets = ExchangePtr((XchgPtr*)&self->Presets, NULL);
+ num_presets = ExchangeInt(&self->NumPresets, 0);
+
+ for(i = 0;i < num_presets;i++)
+ {
+ ALsfpreset *preset = presets[i];
+ ALfontsound **sounds;
+ ALsizei num_sounds;
+ ALboolean deleting;
+ ALsizei j;
+
+ sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
+ num_sounds = ExchangeInt(&preset->NumSounds, 0);
+ DeletePreset(preset, device);
+ preset = NULL;
+
+ for(j = 0;j < num_sounds;j++)
+ DecrementRef(&sounds[j]->ref);
+ /* Some fontsounds may not be immediately deletable because they're
+ * linked to another fontsound. When those fontsounds are deleted
+ * they should become deletable, so use a loop until all fontsounds
+ * are deleted. */
+ do {
+ deleting = AL_FALSE;
+ for(j = 0;j < num_sounds;j++)
+ {
+ if(sounds[j] && sounds[j]->ref == 0)
+ {
+ deleting = AL_TRUE;
+ RemoveFontsound(device, sounds[j]->id);
+ ALfontsound_Destruct(sounds[j]);
+ free(sounds[j]);
+ sounds[j] = NULL;
+ }
+ }
+ } while(deleting);
+ free(sounds);
+ }
+
+ ALsoundfont_Destruct(self);
+ free(self);
+}
+
+
+static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr)
+{
+ return fread(buf, 1, bytes, (FILE*)ptr);
+}
+
+
+/* ReleaseALSoundfonts
+ *
+ * Called to destroy any soundfonts that still exist on the device
+ */
+void ReleaseALSoundfonts(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->SfontMap.size;i++)
+ {
+ ALsoundfont *temp = device->SfontMap.array[i].value;
+ device->SfontMap.array[i].value = NULL;
+
+ ALsoundfont_Destruct(temp);
+
+ memset(temp, 0, sizeof(*temp));
+ free(temp);
+ }
+}
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index 5dbea314..543910db 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -47,6 +47,9 @@ const ALsizei ResamplerPrePadding[ResamplerMax] = {
};
+extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
+extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
+
static ALvoid InitSourceParams(ALsource *Source);
static ALint64 GetSourceOffset(const ALsource *Source);
static ALdouble GetSourceSecOffset(const ALsource *Source);
@@ -145,13 +148,13 @@ typedef enum SrcIntProp {
siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
} SrcIntProp;
-static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
-static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
-static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
+static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
+static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
+static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
-static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
-static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
-static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
+static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
+static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
+static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
static ALint FloatValsByProp(ALenum prop)
{
@@ -344,17 +347,12 @@ static ALint Int64ValsByProp(ALenum prop)
}
-#define RETERR(x) do { \
- alSetError(Context, (x)); \
- return (x); \
-} while(0)
-
#define CHECKVAL(x) do { \
if(!(x)) \
- RETERR(AL_INVALID_VALUE); \
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
} while(0)
-static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
+static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
{
ALint ival;
@@ -365,98 +363,98 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
Source->Pitch = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_INNER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->InnerAngle = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->OuterAngle = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_GAIN:
CHECKVAL(*values >= 0.0f);
Source->Gain = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->MaxDistance = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f);
Source->RollOffFactor = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_REFERENCE_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->RefDistance = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MIN_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->MinGain = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->MaxGain = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGain = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_GAINHF:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGainHF = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AIR_ABSORPTION_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->AirAbsorptionFactor = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_ROOM_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->RoomRolloffFactor = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DOPPLER_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->DopplerFactor = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
@@ -473,16 +471,16 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
if(ApplyOffset(Source) == AL_FALSE)
{
UnlockContext(Context);
- RETERR(AL_INVALID_VALUE);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
}
}
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SEC_OFFSET_LATENCY_SOFT:
/* Query only */
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
case AL_POSITION:
@@ -494,7 +492,7 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
Source->Position[2] = values[2];
UnlockContext(Context);
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_VELOCITY:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
@@ -505,7 +503,7 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
Source->Velocity[2] = values[2];
UnlockContext(Context);
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECTION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
@@ -516,12 +514,12 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
Source->Orientation[2] = values[2];
UnlockContext(Context);
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case sfSampleRWOffsetsSOFT:
case sfByteRWOffsetsSOFT:
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
case sfSourceRelative:
@@ -534,20 +532,20 @@ static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp pr
case sfAuxSendFilterGainHFAuto:
case sfDirectChannelsSOFT:
ival = (ALint)values[0];
- return SetSourceiv(Source, Context, prop, &ival);
+ return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
case sfBuffer:
case sfBuffersQueued:
case sfBuffersProcessed:
ival = (ALint)((ALuint)values[0]);
- return SetSourceiv(Source, Context, prop, &ival);
+ return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
+static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
{
ALCdevice *device = Context->Device;
ALbuffer *buffer = NULL;
@@ -563,13 +561,13 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
Source->HeadRelative = (ALboolean)*values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_LOOPING:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->Looping = (ALboolean)*values;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_BUFFER:
CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
@@ -578,7 +576,7 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
{
UnlockContext(Context);
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
}
Source->BuffersInQueue = 0;
@@ -629,14 +627,14 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
free(temp);
}
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case siSourceState:
case siSourceType:
case siBuffersQueued:
case siBuffersProcessed:
/* Query only */
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
@@ -653,17 +651,17 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
if(ApplyOffset(Source) == AL_FALSE)
{
UnlockContext(Context);
- RETERR(AL_INVALID_VALUE);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
}
}
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case siSampleRWOffsetsSOFT:
case siByteRWOffsetsSOFT:
/* Query only */
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
case AL_DIRECT_FILTER:
@@ -682,35 +680,35 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
}
UnlockContext(Context);
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECT_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DryGainHFAuto = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainAuto = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainHFAuto = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECT_CHANNELS_SOFT:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DirectChannels = *values;
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DISTANCE_MODEL:
CHECKVAL(*values == AL_NONE ||
@@ -724,7 +722,7 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
Source->DistanceModel = *values;
if(Context->SourceDistanceModel)
Source->NeedsUpdate = AL_TRUE;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER:
@@ -734,7 +732,7 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
{
UnlockContext(Context);
- RETERR(AL_INVALID_VALUE);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
}
/* Add refcount on the new slot, and release the previous slot */
@@ -755,7 +753,7 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
}
Source->NeedsUpdate = AL_TRUE;
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_DISTANCE:
@@ -781,10 +779,10 @@ static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
+static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
{
ALfloat fvals[3];
ALint ivals[3];
@@ -795,7 +793,7 @@ static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp pr
case siByteRWOffsetsSOFT:
case siSampleOffsetLatencySOFT:
/* Query only */
- RETERR(AL_INVALID_OPERATION);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
/* 1x int */
@@ -858,60 +856,60 @@ static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp pr
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
#undef CHECKVAL
-static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
+static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
{
ALdouble offsets[2];
ALdouble updateLen;
- ALint ivals[3];
- ALenum err;
+ ALint ivals[3];
+ ALboolean err;
switch(prop)
{
case AL_GAIN:
*values = Source->Gain;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_PITCH:
*values = Source->Pitch;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_DISTANCE:
*values = Source->MaxDistance;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_ROLLOFF_FACTOR:
*values = Source->RollOffFactor;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_REFERENCE_DISTANCE:
*values = Source->RefDistance;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_INNER_ANGLE:
*values = Source->InnerAngle;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_ANGLE:
*values = Source->OuterAngle;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MIN_GAIN:
*values = Source->MinGain;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_GAIN:
*values = Source->MaxGain;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_GAIN:
*values = Source->OuterGain;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
@@ -922,23 +920,23 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
GetSourceOffsets(Source, prop, offsets, updateLen);
UnlockContext(Context);
*values = offsets[0];
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_CONE_OUTER_GAINHF:
*values = Source->OuterGainHF;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AIR_ABSORPTION_FACTOR:
*values = Source->AirAbsorptionFactor;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_ROOM_ROLLOFF_FACTOR:
*values = Source->RoomRolloffFactor;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DOPPLER_FACTOR:
*values = Source->DopplerFactor;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
@@ -947,7 +945,7 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
Context->Device->Frequency;
GetSourceOffsets(Source, prop, values, updateLen);
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SEC_OFFSET_LATENCY_SOFT:
LockContext(Context);
@@ -955,7 +953,7 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1000000000.0;
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_POSITION:
LockContext(Context);
@@ -963,7 +961,7 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
values[1] = Source->Position[1];
values[2] = Source->Position[2];
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_VELOCITY:
LockContext(Context);
@@ -971,7 +969,7 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
values[1] = Source->Velocity[1];
values[2] = Source->Velocity[2];
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECTION:
LockContext(Context);
@@ -979,7 +977,7 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
values[1] = Source->Orientation[1];
values[2] = Source->Orientation[2];
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SOURCE_RELATIVE:
case AL_LOOPING:
@@ -993,30 +991,30 @@ static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatP
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
case AL_DISTANCE_MODEL:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
+ if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
*values = (ALdouble)ivals[0];
return err;
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
+static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
{
ALbufferlistitem *BufferList;
ALdouble dvals[3];
- ALenum err;
+ ALboolean err;
switch(prop)
{
case AL_SOURCE_RELATIVE:
*values = Source->HeadRelative;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_LOOPING:
*values = Source->Looping;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_BUFFER:
LockContext(Context);
@@ -1033,15 +1031,15 @@ static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntPro
*values = ((BufferList && BufferList->buffer) ?
BufferList->buffer->id : 0);
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SOURCE_STATE:
*values = Source->state;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_BUFFERS_QUEUED:
*values = Source->BuffersInQueue;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_BUFFERS_PROCESSED:
LockContext(Context);
@@ -1054,31 +1052,31 @@ static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntPro
else
*values = Source->BuffersPlayed;
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_SOURCE_TYPE:
*values = Source->SourceType;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECT_FILTER_GAINHF_AUTO:
*values = Source->DryGainHFAuto;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
*values = Source->WetGainAuto;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
*values = Source->WetGainHFAuto;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DIRECT_CHANNELS_SOFT:
*values = Source->DirectChannels;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_DISTANCE_MODEL:
*values = Source->DistanceModel;
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_DISTANCE:
case AL_ROLLOFF_FACTOR:
@@ -1089,13 +1087,13 @@ static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntPro
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
case AL_DOPPLER_FACTOR:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
*values = (ALint)dvals[0];
return err;
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
{
values[0] = (ALint)dvals[0];
values[1] = (ALint)dvals[1];
@@ -1105,7 +1103,7 @@ static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntPro
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
{
values[0] = (ALint)dvals[0];
values[1] = (ALint)dvals[1];
@@ -1124,14 +1122,14 @@ static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntPro
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
+static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
{
ALdouble dvals[3];
- ALint ivals[3];
- ALenum err;
+ ALint ivals[3];
+ ALboolean err;
switch(prop)
{
@@ -1140,7 +1138,7 @@ static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntP
values[0] = GetSourceOffset(Source);
values[1] = ALCdevice_GetLatency(Context->Device);
UnlockContext(Context);
- return AL_NO_ERROR;
+ return AL_TRUE;
case AL_MAX_DISTANCE:
case AL_ROLLOFF_FACTOR:
@@ -1151,13 +1149,13 @@ static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntP
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
case AL_DOPPLER_FACTOR:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
*values = (ALint64)dvals[0];
return err;
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
{
values[0] = (ALint64)dvals[0];
values[1] = (ALint64)dvals[1];
@@ -1167,7 +1165,7 @@ static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntP
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
+ if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
{
values[0] = (ALint64)dvals[0];
values[1] = (ALint64)dvals[1];
@@ -1186,18 +1184,18 @@ static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntP
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
case AL_DISTANCE_MODEL:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
+ if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
*values = ivals[0];
return err;
case siBuffer:
case siDirectFilter:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
+ if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
*values = ((ALuint*)ivals)[0];
return err;
case siAuxSendFilter:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
+ if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
{
values[0] = ((ALuint*)ivals)[0];
values[1] = ((ALuint*)ivals)[1];
@@ -1207,143 +1205,133 @@ static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntP
}
ERR("Unexpected property: 0x%04x\n", prop);
- RETERR(AL_INVALID_ENUM);
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-#undef RETERR
-
AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
{
- ALCcontext *Context;
- ALsizei cur = 0;
+ ALCcontext *context;
+ ALsizei cur = 0;
+ ALenum err;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(cur = 0;cur < n;cur++)
{
- ALenum err;
-
- CHECK_VALUE(Context, n >= 0);
- for(cur = 0;cur < n;cur++)
+ ALsource *source = al_calloc(16, sizeof(ALsource));
+ if(!source)
{
- ALsource *source = al_calloc(16, sizeof(ALsource));
- if(!source)
- al_throwerr(Context, AL_OUT_OF_MEMORY);
- InitSourceParams(source);
-
- err = NewThunkEntry(&source->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(source->id);
- memset(source, 0, sizeof(ALsource));
- al_free(source);
+ alDeleteSources(cur, sources);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
+ }
+ InitSourceParams(source);
- al_throwerr(Context, err);
- }
+ err = NewThunkEntry(&source->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
+ if(err != AL_NO_ERROR)
+ {
+ FreeThunkEntry(source->id);
+ memset(source, 0, sizeof(ALsource));
+ al_free(source);
- sources[cur] = source->id;
- }
- }
- al_catchany()
- {
- if(cur > 0)
alDeleteSources(cur, sources);
+ SET_ERROR_AND_GOTO(context, err, done);
+ }
+
+ sources[cur] = source->id;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
{
- ALCcontext *Context;
+ ALCcontext *context;
+ ALbufferlistitem *BufferList;
+ ALsource *Source;
+ ALsizei i, j;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALbufferlistitem *BufferList;
- ALsource *Source;
- ALsizei i, j;
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- CHECK_VALUE(Context, n >= 0);
+ /* Check that all Sources are valid */
+ for(i = 0;i < n;i++)
+ {
+ if(LookupSource(context, sources[i]) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
+ for(i = 0;i < n;i++)
+ {
+ ALsource **srclist, **srclistend;
- /* Check that all Sources are valid */
- for(i = 0;i < n;i++)
- {
- if(LookupSource(Context, sources[i]) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if((Source=RemoveSource(context, sources[i])) == NULL)
+ continue;
+ FreeThunkEntry(Source->id);
- for(i = 0;i < n;i++)
+ LockContext(context);
+ srclist = context->ActiveSources;
+ srclistend = srclist + context->ActiveSourceCount;
+ while(srclist != srclistend)
{
- ALsource **srclist, **srclistend;
-
- if((Source=RemoveSource(Context, sources[i])) == NULL)
- continue;
- FreeThunkEntry(Source->id);
-
- LockContext(Context);
- srclist = Context->ActiveSources;
- srclistend = srclist + Context->ActiveSourceCount;
- while(srclist != srclistend)
+ if(*srclist == Source)
{
- if(*srclist == Source)
- {
- Context->ActiveSourceCount--;
- *srclist = *(--srclistend);
- break;
- }
- srclist++;
+ context->ActiveSourceCount--;
+ *srclist = *(--srclistend);
+ break;
}
- UnlockContext(Context);
-
- while(Source->queue != NULL)
- {
- BufferList = Source->queue;
- Source->queue = BufferList->next;
+ srclist++;
+ }
+ UnlockContext(context);
- if(BufferList->buffer != NULL)
- DecrementRef(&BufferList->buffer->ref);
- free(BufferList);
- }
+ while(Source->queue != NULL)
+ {
+ BufferList = Source->queue;
+ Source->queue = BufferList->next;
- for(j = 0;j < MAX_SENDS;++j)
- {
- if(Source->Send[j].Slot)
- DecrementRef(&Source->Send[j].Slot->ref);
- Source->Send[j].Slot = NULL;
- }
+ if(BufferList->buffer != NULL)
+ DecrementRef(&BufferList->buffer->ref);
+ free(BufferList);
+ }
- memset(Source, 0, sizeof(*Source));
- al_free(Source);
+ for(j = 0;j < MAX_SENDS;++j)
+ {
+ if(Source->Send[j].Slot)
+ DecrementRef(&Source->Send[j].Slot->ref);
+ Source->Send[j].Slot = NULL;
}
+
+ memset(Source, 0, sizeof(*Source));
+ al_free(Source);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
{
- ALCcontext *Context;
- ALboolean result;
+ ALCcontext *context;
+ ALboolean ret;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
+ ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
- return result;
+ return ret;
}
@@ -1615,7 +1603,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val
else
{
ALdouble dval;
- if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
+ if(GetSourcedv(Source, Context, param, &dval))
*value = (ALfloat)dval;
}
@@ -1640,7 +1628,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va
else
{
ALdouble dvals[3];
- if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
+ if(GetSourcedv(Source, Context, param, dvals))
{
*value1 = (ALfloat)dvals[0];
*value2 = (ALfloat)dvals[1];
@@ -1670,7 +1658,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va
else
{
ALdouble dvals[3];
- if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
+ if(GetSourcedv(Source, Context, param, dvals))
{
ALint i;
for(i = 0;i < count;i++)
@@ -1719,7 +1707,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble
else
{
ALdouble dvals[3];
- if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
+ if(GetSourcedv(Source, Context, param, dvals))
{
*value1 = dvals[0];
*value2 = dvals[1];
@@ -1789,7 +1777,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1
else
{
ALint ivals[3];
- if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
+ if(GetSourceiv(Source, Context, param, ivals))
{
*value1 = ivals[0];
*value2 = ivals[1];
@@ -1859,7 +1847,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64
else
{
ALint64 i64vals[3];
- if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
+ if(GetSourcei64v(Source, Context, param, i64vals))
{
*value1 = i64vals[0];
*value2 = i64vals[1];
@@ -1897,53 +1885,51 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
}
AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < n;i++)
{
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(!LookupSource(Context, sources[i]))
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!LookupSource(context, sources[i]))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
- LockContext(Context);
- while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
+ LockContext(context);
+ while(n > context->MaxActiveSources-context->ActiveSourceCount)
+ {
+ void *temp = NULL;
+ ALsizei newcount;
+
+ newcount = context->MaxActiveSources << 1;
+ if(newcount > 0)
+ temp = realloc(context->ActiveSources,
+ sizeof(*context->ActiveSources) * newcount);
+ if(!temp)
{
- void *temp = NULL;
- ALsizei newcount;
-
- newcount = Context->MaxActiveSources << 1;
- if(newcount > 0)
- temp = realloc(Context->ActiveSources,
- sizeof(*Context->ActiveSources) * newcount);
- if(!temp)
- {
- UnlockContext(Context);
- al_throwerr(Context, AL_OUT_OF_MEMORY);
- }
-
- Context->ActiveSources = temp;
- Context->MaxActiveSources = newcount;
+ UnlockContext(context);
+ SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
- for(i = 0;i < n;i++)
- {
- Source = LookupSource(Context, sources[i]);
- if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
- else SetSourceState(Source, Context, AL_PLAYING);
- }
- UnlockContext(Context);
+ context->ActiveSources = temp;
+ context->MaxActiveSources = newcount;
}
- al_endtry;
- ALCcontext_DecRef(Context);
+ for(i = 0;i < n;i++)
+ {
+ source = LookupSource(context, sources[i]);
+ if(context->DeferUpdates) source->new_state = AL_PLAYING;
+ else SetSourceState(source, context, AL_PLAYING);
+ }
+ UnlockContext(context);
+
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
@@ -1952,34 +1938,32 @@ AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
}
AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < n;i++)
{
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(!LookupSource(Context, sources[i]))
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!LookupSource(context, sources[i]))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
- LockContext(Context);
- for(i = 0;i < n;i++)
- {
- Source = LookupSource(Context, sources[i]);
- if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
- else SetSourceState(Source, Context, AL_PAUSED);
- }
- UnlockContext(Context);
+ LockContext(context);
+ for(i = 0;i < n;i++)
+ {
+ source = LookupSource(context, sources[i]);
+ if(context->DeferUpdates) source->new_state = AL_PAUSED;
+ else SetSourceState(source, context, AL_PAUSED);
}
- al_endtry;
+ UnlockContext(context);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
@@ -1988,34 +1972,32 @@ AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
}
AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < n;i++)
{
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(!LookupSource(Context, sources[i]))
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!LookupSource(context, sources[i]))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
- LockContext(Context);
- for(i = 0;i < n;i++)
- {
- Source = LookupSource(Context, sources[i]);
- Source->new_state = AL_NONE;
- SetSourceState(Source, Context, AL_STOPPED);
- }
- UnlockContext(Context);
+ LockContext(context);
+ for(i = 0;i < n;i++)
+ {
+ source = LookupSource(context, sources[i]);
+ source->new_state = AL_NONE;
+ SetSourceState(source, context, AL_STOPPED);
}
- al_endtry;
+ UnlockContext(context);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
@@ -2024,226 +2006,217 @@ AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
}
AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(n >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < n;i++)
{
- CHECK_VALUE(Context, n >= 0);
- for(i = 0;i < n;i++)
- {
- if(!LookupSource(Context, sources[i]))
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ if(!LookupSource(context, sources[i]))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
- LockContext(Context);
- for(i = 0;i < n;i++)
- {
- Source = LookupSource(Context, sources[i]);
- Source->new_state = AL_NONE;
- SetSourceState(Source, Context, AL_INITIAL);
- }
- UnlockContext(Context);
+ LockContext(context);
+ for(i = 0;i < n;i++)
+ {
+ source = LookupSource(context, sources[i]);
+ source->new_state = AL_NONE;
+ SetSourceState(source, context, AL_INITIAL);
}
- al_endtry;
+ UnlockContext(context);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
-AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
+AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCdevice *device;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
ALbufferlistitem *BufferListStart = NULL;
ALbufferlistitem *BufferList;
- ALbuffer *BufferFmt;
+ ALbuffer *BufferFmt = NULL;
if(nb == 0)
return;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- ALCdevice *device = Context->Device;
+ device = context->Device;
- CHECK_VALUE(Context, nb >= 0);
+ if(!(nb >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ if((source=LookupSource(context, src)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if((Source=LookupSource(Context, source)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ LockContext(context);
+ if(source->SourceType == AL_STATIC)
+ {
+ UnlockContext(context);
+ /* Can't queue on a Static Source */
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
+ }
- LockContext(Context);
- if(Source->SourceType == AL_STATIC)
+ /* Check for a valid Buffer, for its frequency and format */
+ BufferList = source->queue;
+ while(BufferList)
+ {
+ if(BufferList->buffer)
{
- UnlockContext(Context);
- /* Can't queue on a Static Source */
- al_throwerr(Context, AL_INVALID_OPERATION);
+ BufferFmt = BufferList->buffer;
+ break;
}
+ BufferList = BufferList->next;
+ }
- BufferFmt = NULL;
+ for(i = 0;i < nb;i++)
+ {
+ ALbuffer *buffer = NULL;
+ if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
+ {
+ UnlockContext(context);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+ }
- /* Check for a valid Buffer, for its frequency and format */
- BufferList = Source->queue;
- while(BufferList)
+ if(!BufferListStart)
{
- if(BufferList->buffer)
- {
- BufferFmt = BufferList->buffer;
- break;
- }
+ BufferListStart = malloc(sizeof(ALbufferlistitem));
+ BufferListStart->buffer = buffer;
+ BufferListStart->next = NULL;
+ BufferListStart->prev = NULL;
+ BufferList = BufferListStart;
+ }
+ else
+ {
+ BufferList->next = malloc(sizeof(ALbufferlistitem));
+ BufferList->next->buffer = buffer;
+ BufferList->next->next = NULL;
+ BufferList->next->prev = BufferList;
BufferList = BufferList->next;
}
+ if(!buffer) continue;
+ IncrementRef(&buffer->ref);
- for(i = 0;i < nb;i++)
+ ReadLock(&buffer->lock);
+ if(BufferFmt == NULL)
{
- ALbuffer *buffer = NULL;
- if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
- {
- UnlockContext(Context);
- al_throwerr(Context, AL_INVALID_NAME);
- }
+ BufferFmt = buffer;
- if(!BufferListStart)
- {
- BufferListStart = malloc(sizeof(ALbufferlistitem));
- BufferListStart->buffer = buffer;
- BufferListStart->next = NULL;
- BufferListStart->prev = NULL;
- BufferList = BufferListStart;
- }
+ source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
+ source->SampleSize = BytesFromFmt(buffer->FmtType);
+ if(buffer->FmtChannels == FmtMono)
+ source->Update = CalcSourceParams;
else
- {
- BufferList->next = malloc(sizeof(ALbufferlistitem));
- BufferList->next->buffer = buffer;
- BufferList->next->next = NULL;
- BufferList->next->prev = BufferList;
- BufferList = BufferList->next;
- }
- if(!buffer) continue;
- IncrementRef(&buffer->ref);
-
- ReadLock(&buffer->lock);
- if(BufferFmt == NULL)
- {
- BufferFmt = buffer;
+ source->Update = CalcNonAttnSourceParams;
- Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
- Source->SampleSize = BytesFromFmt(buffer->FmtType);
- if(buffer->FmtChannels == FmtMono)
- Source->Update = CalcSourceParams;
- else
- Source->Update = CalcNonAttnSourceParams;
-
- Source->NeedsUpdate = AL_TRUE;
- }
- else if(BufferFmt->Frequency != buffer->Frequency ||
- BufferFmt->OriginalChannels != buffer->OriginalChannels ||
- BufferFmt->OriginalType != buffer->OriginalType)
- {
- ReadUnlock(&buffer->lock);
- UnlockContext(Context);
- al_throwerr(Context, AL_INVALID_OPERATION);
- }
+ source->NeedsUpdate = AL_TRUE;
+ }
+ else if(BufferFmt->Frequency != buffer->Frequency ||
+ BufferFmt->OriginalChannels != buffer->OriginalChannels ||
+ BufferFmt->OriginalType != buffer->OriginalType)
+ {
ReadUnlock(&buffer->lock);
+ UnlockContext(context);
+ SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
+ ReadUnlock(&buffer->lock);
+ }
- /* Source is now streaming */
- Source->SourceType = AL_STREAMING;
+ /* Source is now streaming */
+ source->SourceType = AL_STREAMING;
- if(Source->queue == NULL)
- Source->queue = BufferListStart;
- else
- {
- /* Append to the end of the queue */
- BufferList = Source->queue;
- while(BufferList->next != NULL)
- BufferList = BufferList->next;
+ if(source->queue == NULL)
+ source->queue = BufferListStart;
+ else
+ {
+ /* Append to the end of the queue */
+ BufferList = source->queue;
+ while(BufferList->next != NULL)
+ BufferList = BufferList->next;
- BufferListStart->prev = BufferList;
- BufferList->next = BufferListStart;
- }
+ BufferListStart->prev = BufferList;
+ BufferList->next = BufferListStart;
+ }
+ BufferListStart = NULL;
- Source->BuffersInQueue += nb;
+ source->BuffersInQueue += nb;
- UnlockContext(Context);
- }
- al_catchany()
+ UnlockContext(context);
+
+done:
+ while(BufferListStart)
{
- while(BufferListStart)
- {
- BufferList = BufferListStart;
- BufferListStart = BufferList->next;
+ BufferList = BufferListStart;
+ BufferListStart = BufferList->next;
- if(BufferList->buffer)
- DecrementRef(&BufferList->buffer->ref);
- free(BufferList);
- }
+ if(BufferList->buffer)
+ DecrementRef(&BufferList->buffer->ref);
+ free(BufferList);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
}
-AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
+AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
{
- ALCcontext *Context;
- ALsource *Source;
- ALsizei i;
+ ALCcontext *context;
+ ALsource *source;
+ ALsizei i;
ALbufferlistitem *BufferList;
if(nb == 0)
return;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
+
+ if(!(nb >= 0))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- al_try
+ if((source=LookupSource(context, src)) == NULL)
+ SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
+
+ LockContext(context);
+ if(source->Looping || source->SourceType != AL_STREAMING ||
+ (ALuint)nb > source->BuffersPlayed)
{
- CHECK_VALUE(Context, nb >= 0);
+ UnlockContext(context);
+ /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ }
- if((Source=LookupSource(Context, source)) == NULL)
- al_throwerr(Context, AL_INVALID_NAME);
+ for(i = 0;i < nb;i++)
+ {
+ BufferList = source->queue;
+ source->queue = BufferList->next;
+ source->BuffersInQueue--;
+ source->BuffersPlayed--;
- LockContext(Context);
- if(Source->Looping || Source->SourceType != AL_STREAMING ||
- (ALuint)nb > Source->BuffersPlayed)
+ if(BufferList->buffer)
{
- UnlockContext(Context);
- /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
- al_throwerr(Context, AL_INVALID_VALUE);
+ buffers[i] = BufferList->buffer->id;
+ DecrementRef(&BufferList->buffer->ref);
}
+ else
+ buffers[i] = 0;
- for(i = 0;i < nb;i++)
- {
- BufferList = Source->queue;
- Source->queue = BufferList->next;
- Source->BuffersInQueue--;
- Source->BuffersPlayed--;
-
- if(BufferList->buffer)
- {
- buffers[i] = BufferList->buffer->id;
- DecrementRef(&BufferList->buffer->ref);
- }
- else
- buffers[i] = 0;
-
- free(BufferList);
- }
- if(Source->queue)
- Source->queue->prev = NULL;
- UnlockContext(Context);
+ free(BufferList);
}
- al_endtry;
+ if(source->queue)
+ source->queue->prev = NULL;
+ UnlockContext(context);
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
@@ -2328,7 +2301,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
if(Source->state != AL_PLAYING)
{
- for(j = 0;j < MaxChannels;j++)
+ for(j = 0;j < MAX_INPUT_CHANNELS;j++)
{
for(k = 0;k < SRC_HISTORY_LENGTH;k++)
Source->Hrtf.History[j][k] = 0.0f;
@@ -2432,7 +2405,7 @@ static ALint64 GetSourceOffset(const ALsource *Source)
BufferList = BufferList->next;
}
- return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
+ return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
}
/* GetSourceSecOffset
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
index 678e9e94..280dd896 100644
--- a/OpenAL32/alState.c
+++ b/OpenAL32/alState.c
@@ -23,10 +23,14 @@
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
+#include "AL/al.h"
#include "AL/alext.h"
#include "alError.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
+#include "alMidi.h"
+
+#include "midi/base.h"
static const ALchar alVendor[] = "OpenAL Community";
@@ -43,260 +47,334 @@ static const ALchar alErrOutOfMemory[] = "Out of Memory";
AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(capability)
{
- switch(capability)
- {
- case AL_SOURCE_DISTANCE_MODEL:
- Context->SourceDistanceModel = AL_TRUE;
- Context->UpdateSources = AL_TRUE;
- break;
+ case AL_SOURCE_DISTANCE_MODEL:
+ context->SourceDistanceModel = AL_TRUE;
+ context->UpdateSources = AL_TRUE;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(capability)
{
- switch(capability)
- {
- case AL_SOURCE_DISTANCE_MODEL:
- Context->SourceDistanceModel = AL_FALSE;
- Context->UpdateSources = AL_TRUE;
- break;
+ case AL_SOURCE_DISTANCE_MODEL:
+ context->SourceDistanceModel = AL_FALSE;
+ context->UpdateSources = AL_TRUE;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
{
- ALCcontext *Context;
+ ALCcontext *context;
ALboolean value=AL_FALSE;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- al_try
+ switch(capability)
{
- switch(capability)
- {
- case AL_SOURCE_DISTANCE_MODEL:
- value = Context->SourceDistanceModel;
- break;
+ case AL_SOURCE_DISTANCE_MODEL:
+ value = context->SourceDistanceModel;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
{
- ALCcontext *Context;
+ ALCcontext *context;
ALboolean value=AL_FALSE;
- Context = GetContextRef();
- if(!Context) return AL_FALSE;
+ context = GetContextRef();
+ if(!context) return AL_FALSE;
- al_try
+ switch(pname)
{
- switch(pname)
- {
- case AL_DOPPLER_FACTOR:
- if(Context->DopplerFactor != 0.0f)
- value = AL_TRUE;
- break;
-
- case AL_DOPPLER_VELOCITY:
- if(Context->DopplerVelocity != 0.0f)
- value = AL_TRUE;
- break;
-
- case AL_DISTANCE_MODEL:
- if(Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
- value = AL_TRUE;
- break;
-
- case AL_SPEED_OF_SOUND:
- if(Context->SpeedOfSound != 0.0f)
- value = AL_TRUE;
- break;
-
- case AL_DEFERRED_UPDATES_SOFT:
- value = Context->DeferUpdates;
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_DOPPLER_FACTOR:
+ if(context->DopplerFactor != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ if(context->DopplerVelocity != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
+ value = AL_TRUE;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ if(context->SpeedOfSound != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_DEFERRED_UPDATES_SOFT:
+ value = context->DeferUpdates;
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
ALdouble value = 0.0;
- Context = GetContextRef();
- if(!Context) return 0.0;
+ context = GetContextRef();
+ if(!context) return 0.0;
- al_try
+ switch(pname)
{
- switch(pname)
- {
- case AL_DOPPLER_FACTOR:
- value = (ALdouble)Context->DopplerFactor;
- break;
-
- case AL_DOPPLER_VELOCITY:
- value = (ALdouble)Context->DopplerVelocity;
- break;
-
- case AL_DISTANCE_MODEL:
- value = (ALdouble)Context->DistanceModel;
- break;
-
- case AL_SPEED_OF_SOUND:
- value = (ALdouble)Context->SpeedOfSound;
- break;
-
- case AL_DEFERRED_UPDATES_SOFT:
- value = (ALdouble)Context->DeferUpdates;
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_DOPPLER_FACTOR:
+ value = (ALdouble)context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (ALdouble)context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALdouble)context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (ALdouble)context->SpeedOfSound;
+ break;
+
+ case AL_DEFERRED_UPDATES_SOFT:
+ value = (ALdouble)context->DeferUpdates;
+ break;
+
+ case AL_MIDI_GAIN_SOFT:
+ device = context->Device;
+ value = (ALdouble)MidiSynth_getGain(device->Synth);
+ break;
+
+ case AL_MIDI_STATE_SOFT:
+ device = context->Device;
+ value = (ALdouble)MidiSynth_getState(device->Synth);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
{
- ALCcontext *Context;
+ ALCdevice *device;
+ ALCcontext *context;
ALfloat value = 0.0f;
- Context = GetContextRef();
- if(!Context) return 0.0f;
+ context = GetContextRef();
+ if(!context) return 0.0f;
- al_try
+ switch(pname)
{
- switch(pname)
- {
- case AL_DOPPLER_FACTOR:
- value = Context->DopplerFactor;
- break;
-
- case AL_DOPPLER_VELOCITY:
- value = Context->DopplerVelocity;
- break;
-
- case AL_DISTANCE_MODEL:
- value = (ALfloat)Context->DistanceModel;
- break;
-
- case AL_SPEED_OF_SOUND:
- value = Context->SpeedOfSound;
- break;
-
- case AL_DEFERRED_UPDATES_SOFT:
- value = (ALfloat)Context->DeferUpdates;
- break;
-
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ case AL_DOPPLER_FACTOR:
+ value = context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALfloat)context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = context->SpeedOfSound;
+ break;
+
+ case AL_DEFERRED_UPDATES_SOFT:
+ value = (ALfloat)context->DeferUpdates;
+ break;
+
+ case AL_MIDI_GAIN_SOFT:
+ device = context->Device;
+ value = MidiSynth_getGain(device->Synth);
+ break;
+
+ case AL_MIDI_STATE_SOFT:
+ device = context->Device;
+ value = (ALfloat)MidiSynth_getState(device->Synth);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
{
- ALCcontext *Context;
+ ALCcontext *context;
+ ALCdevice *device;
+ MidiSynth *synth;
ALint value = 0;
- Context = GetContextRef();
- if(!Context) return 0;
+ context = GetContextRef();
+ if(!context) return 0;
- al_try
+ switch(pname)
{
- switch(pname)
- {
- case AL_DOPPLER_FACTOR:
- value = (ALint)Context->DopplerFactor;
- break;
+ case AL_DOPPLER_FACTOR:
+ value = (ALint)context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (ALint)context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALint)context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (ALint)context->SpeedOfSound;
+ break;
+
+ case AL_DEFERRED_UPDATES_SOFT:
+ value = (ALint)context->DeferUpdates;
+ break;
+
+ case AL_SOUNDFONTS_SIZE_SOFT:
+ device = context->Device;
+ synth = device->Synth;
+ value = synth->NumSoundfonts;
+ break;
+
+ case AL_MIDI_STATE_SOFT:
+ device = context->Device;
+ value = MidiSynth_getState(device->Synth);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
- case AL_DOPPLER_VELOCITY:
- value = (ALint)Context->DopplerVelocity;
- break;
+done:
+ ALCcontext_DecRef(context);
- case AL_DISTANCE_MODEL:
- value = (ALint)Context->DistanceModel;
- break;
+ return value;
+}
- case AL_SPEED_OF_SOUND:
- value = (ALint)Context->SpeedOfSound;
- break;
+AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
+{
+ ALCcontext *context;
+ ALCdevice *device;
+ MidiSynth *synth;
+ ALint64SOFT value = 0;
- case AL_DEFERRED_UPDATES_SOFT:
- value = (ALint)Context->DeferUpdates;
- break;
+ context = GetContextRef();
+ if(!context) return 0;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ value = (ALint64SOFT)context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (ALint64SOFT)context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALint64SOFT)context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (ALint64SOFT)context->SpeedOfSound;
+ break;
+
+ case AL_DEFERRED_UPDATES_SOFT:
+ value = (ALint64SOFT)context->DeferUpdates;
+ break;
+
+ case AL_MIDI_CLOCK_SOFT:
+ device = context->Device;
+ ALCdevice_Lock(device);
+ value = MidiSynth_getTime(device->Synth);
+ ALCdevice_Unlock(device);
+ break;
+
+ case AL_SOUNDFONTS_SIZE_SOFT:
+ device = context->Device;
+ synth = device->Synth;
+ value = (ALint64SOFT)synth->NumSoundfonts;
+ break;
+
+ case AL_MIDI_STATE_SOFT:
+ device = context->Device;
+ value = (ALint64SOFT)MidiSynth_getState(device->Synth);
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
if(values)
{
@@ -312,26 +390,24 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(pname)
{
- CHECK_VALUE(Context, values);
- switch(pname)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
if(values)
{
@@ -342,31 +418,31 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_MIDI_GAIN_SOFT:
+ case AL_MIDI_STATE_SOFT:
values[0] = alGetDouble(pname);
return;
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(pname)
{
- CHECK_VALUE(Context, values);
- switch(pname)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
if(values)
{
@@ -377,31 +453,34 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_MIDI_GAIN_SOFT:
+ case AL_MIDI_STATE_SOFT:
values[0] = alGetFloat(pname);
return;
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ switch(pname)
{
- CHECK_VALUE(Context, values);
- switch(pname)
- {
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
{
- ALCcontext *Context;
+ ALCcontext *context;
+ ALCdevice *device;
+ MidiSynth *synth;
+ ALsizei i;
if(values)
{
@@ -412,187 +491,228 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
+ case AL_SOUNDFONTS_SIZE_SOFT:
+ case AL_MIDI_STATE_SOFT:
values[0] = alGetInteger(pname);
return;
}
}
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
+ switch(pname)
+ {
+ case AL_SOUNDFONTS_SOFT:
+ device = context->Device;
+ synth = device->Synth;
+ if(synth->NumSoundfonts > 0)
+ {
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < synth->NumSoundfonts;i++)
+ values[i] = synth->Soundfonts[i]->id;
+ }
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
+}
+
+AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
+{
+ ALCcontext *context;
+ ALCdevice *device;
+ MidiSynth *synth;
+ ALsizei i;
+
+ if(values)
{
- CHECK_VALUE(Context, values);
switch(pname)
{
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
+ case AL_DOPPLER_FACTOR:
+ case AL_DOPPLER_VELOCITY:
+ case AL_DISTANCE_MODEL:
+ case AL_SPEED_OF_SOUND:
+ case AL_DEFERRED_UPDATES_SOFT:
+ case AL_MIDI_CLOCK_SOFT:
+ case AL_SOUNDFONTS_SIZE_SOFT:
+ case AL_MIDI_STATE_SOFT:
+ values[0] = alGetInteger64SOFT(pname);
+ return;
}
}
- al_endtry;
- ALCcontext_DecRef(Context);
+ context = GetContextRef();
+ if(!context) return;
+
+ switch(pname)
+ {
+ case AL_SOUNDFONTS_SOFT:
+ device = context->Device;
+ synth = device->Synth;
+ if(synth->NumSoundfonts > 0)
+ {
+ if(!(values))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+ for(i = 0;i < synth->NumSoundfonts;i++)
+ values[i] = (ALint64SOFT)synth->Soundfonts[i]->id;
+ }
+ break;
+
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
+ }
+
+done:
+ ALCcontext_DecRef(context);
}
AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
{
- const ALchar *value;
- ALCcontext *Context;
+ const ALchar *value = NULL;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return NULL;
+ context = GetContextRef();
+ if(!context) return NULL;
- al_try
+ switch(pname)
{
- switch(pname)
- {
- case AL_VENDOR:
- value = alVendor;
- break;
+ case AL_VENDOR:
+ value = alVendor;
+ break;
- case AL_VERSION:
- value = alVersion;
- break;
+ case AL_VERSION:
+ value = alVersion;
+ break;
- case AL_RENDERER:
- value = alRenderer;
- break;
+ case AL_RENDERER:
+ value = alRenderer;
+ break;
- case AL_EXTENSIONS:
- value = Context->ExtensionList;
- break;
+ case AL_EXTENSIONS:
+ value = context->ExtensionList;
+ break;
- case AL_NO_ERROR:
- value = alNoError;
- break;
+ case AL_NO_ERROR:
+ value = alNoError;
+ break;
- case AL_INVALID_NAME:
- value = alErrInvalidName;
- break;
+ case AL_INVALID_NAME:
+ value = alErrInvalidName;
+ break;
- case AL_INVALID_ENUM:
- value = alErrInvalidEnum;
- break;
+ case AL_INVALID_ENUM:
+ value = alErrInvalidEnum;
+ break;
- case AL_INVALID_VALUE:
- value = alErrInvalidValue;
- break;
+ case AL_INVALID_VALUE:
+ value = alErrInvalidValue;
+ break;
- case AL_INVALID_OPERATION:
- value = alErrInvalidOp;
- break;
+ case AL_INVALID_OPERATION:
+ value = alErrInvalidOp;
+ break;
- case AL_OUT_OF_MEMORY:
- value = alErrOutOfMemory;
- break;
+ case AL_OUT_OF_MEMORY:
+ value = alErrOutOfMemory;
+ break;
- default:
- al_throwerr(Context, AL_INVALID_ENUM);
- }
- }
- al_catchany()
- {
- value = NULL;
+ default:
+ SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
- al_endtry;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
return value;
}
AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- CHECK_VALUE(Context, value >= 0.0f && isfinite(value));
+ if(!(value >= 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Context->DopplerFactor = value;
- Context->UpdateSources = AL_TRUE;
- }
- al_endtry;
+ context->DopplerFactor = value;
+ context->UpdateSources = AL_TRUE;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- CHECK_VALUE(Context, value >= 0.0f && isfinite(value));
+ if(!(value >= 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Context->DopplerVelocity = value;
- Context->UpdateSources = AL_TRUE;
- }
- al_endtry;
+ context->DopplerVelocity = value;
+ context->UpdateSources = AL_TRUE;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- CHECK_VALUE(Context, value > 0.0f && isfinite(value));
+ if(!(value > 0.0f && isfinite(value)))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- Context->SpeedOfSound = value;
- Context->UpdateSources = AL_TRUE;
- }
- al_endtry;
+ context->SpeedOfSound = value;
+ context->UpdateSources = AL_TRUE;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- al_try
- {
- CHECK_VALUE(Context, value == AL_NONE ||
- value == AL_INVERSE_DISTANCE ||
- value == AL_INVERSE_DISTANCE_CLAMPED ||
- value == AL_LINEAR_DISTANCE ||
- value == AL_LINEAR_DISTANCE_CLAMPED ||
- value == AL_EXPONENT_DISTANCE ||
- value == AL_EXPONENT_DISTANCE_CLAMPED);
-
- Context->DistanceModel = value;
- if(!Context->SourceDistanceModel)
- Context->UpdateSources = AL_TRUE;
- }
- al_endtry;
+ if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED ||
+ value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
+ value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
+ value == AL_NONE))
+ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
+
+ context->DistanceModel = value;
+ if(!context->SourceDistanceModel)
+ context->UpdateSources = AL_TRUE;
- ALCcontext_DecRef(Context);
+done:
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- if(!Context->DeferUpdates)
+ if(!context->DeferUpdates)
{
ALboolean UpdateSources;
ALsource **src, **src_end;
@@ -601,61 +721,61 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
SetMixerFPUMode(&oldMode);
- LockContext(Context);
- Context->DeferUpdates = AL_TRUE;
+ LockContext(context);
+ context->DeferUpdates = AL_TRUE;
/* Make sure all pending updates are performed */
- UpdateSources = ExchangeInt(&Context->UpdateSources, AL_FALSE);
+ UpdateSources = ExchangeInt(&context->UpdateSources, AL_FALSE);
- src = Context->ActiveSources;
- src_end = src + Context->ActiveSourceCount;
+ src = context->ActiveSources;
+ src_end = src + context->ActiveSourceCount;
while(src != src_end)
{
if((*src)->state != AL_PLAYING)
{
- Context->ActiveSourceCount--;
+ context->ActiveSourceCount--;
*src = *(--src_end);
continue;
}
if(ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) || UpdateSources)
- ALsource_Update(*src, Context);
+ ALsource_Update(*src, context);
src++;
}
- slot = Context->ActiveEffectSlots;
- slot_end = slot + Context->ActiveEffectSlotCount;
+ slot = context->ActiveEffectSlots;
+ slot_end = slot + context->ActiveEffectSlotCount;
while(slot != slot_end)
{
if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- ALeffectState_Update((*slot)->EffectState, Context->Device, *slot);
+ V((*slot)->EffectState,update)(context->Device, *slot);
slot++;
}
- UnlockContext(Context);
+ UnlockContext(context);
RestoreFPUMode(&oldMode);
}
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
{
- ALCcontext *Context;
+ ALCcontext *context;
- Context = GetContextRef();
- if(!Context) return;
+ context = GetContextRef();
+ if(!context) return;
- if(ExchangeInt(&Context->DeferUpdates, AL_FALSE))
+ if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
{
ALsizei pos;
- LockContext(Context);
- LockUIntMapRead(&Context->SourceMap);
- for(pos = 0;pos < Context->SourceMap.size;pos++)
+ LockContext(context);
+ LockUIntMapRead(&context->SourceMap);
+ for(pos = 0;pos < context->SourceMap.size;pos++)
{
- ALsource *Source = Context->SourceMap.array[pos].value;
+ ALsource *Source = context->SourceMap.array[pos].value;
ALenum new_state;
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
@@ -664,11 +784,11 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
new_state = ExchangeInt(&Source->new_state, AL_NONE);
if(new_state)
- SetSourceState(Source, Context, new_state);
+ SetSourceState(Source, context, new_state);
}
- UnlockUIntMapRead(&Context->SourceMap);
- UnlockContext(Context);
+ UnlockUIntMapRead(&context->SourceMap);
+ UnlockContext(context);
}
- ALCcontext_DecRef(Context);
+ ALCcontext_DecRef(context);
}
diff --git a/alsoftrc.sample b/alsoftrc.sample
index dd5ae4db..64590357 100644
--- a/alsoftrc.sample
+++ b/alsoftrc.sample
@@ -14,7 +14,7 @@
## disable-cpu-exts:
# Disables use of the listed CPU extensions. Certain methods may utilize CPU
# extensions when detected, and this option is useful for preventing those
-# extensions from being used. The available extensions are: sse, neon.
+# extensions from being used. The available extensions are: sse, sse2, neon.
# Specifying 'all' disables use of all extensions.
#disable-cpu-exts =
@@ -121,13 +121,13 @@
# followed by all other available backends, while 'oss' will list OSS only).
# Backends prepended with - won't be available for use (eg. '-oss,' will allow
# all available backends except OSS). An empty list means the default.
-#drivers = pulse,alsa,core,oss,solaris,sndio,mmdevapi,dsound,winmm,port,opensl,null,wave
+#drivers = pulse,alsa,core,oss,solaris,sndio,qsa,mmdevapi,dsound,winmm,port,opensl,null,wave
## excludefx:
# Sets which effects to exclude, preventing apps from using them. This can
# help for apps that try to use effects which are too CPU intensive for the
-# system to handle. Available effects are: eaxreverb,reverb,echo,modulator,
-# dedicated
+# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus,
+# compressor,distortion,echo,equalizer,flanger,modulator,dedicated
#excludefx =
## slots:
@@ -184,6 +184,23 @@
#trap-al-error = false
##
+## MIDI stuff (EXPERIMENTAL)
+##
+[midi]
+
+## soundfont:
+# A default soundfont (sf2 format). Used when an app requests the system
+# default.
+#soundfont =
+
+## volume:
+# Additional attenuation applied to MIDI output, expressed in decibels. This
+# is used to help keep the mix from clipping, and so must be 0 or less. The
+# value is logarithmic, so -6 will be about half amplitude, and -12 about
+# 1/4th. The default is roughly -13.9794 (0.2, or 1/5th).
+#volume =
+
+##
## Reverb effect stuff (includes EAX reverb)
##
[reverb]
@@ -202,6 +219,24 @@
#emulate-eax = false
##
+## PulseAudio backend stuff
+##
+[pulse]
+
+## spawn-server:
+# Attempts to autospawn a PulseAudio server whenever needed (initializing the
+# backend, enumerating devices, etc). Setting autospawn to false in Pulse's
+# client.conf will still prevent autospawning even if this is set to true.
+#spawn-server = true
+
+## allow-moves:
+# Allows PulseAudio to move active streams to different devices. Note that the
+# device specifier (seen by applications) will not be updated when this
+# occurs, and neither will the AL device configuration (sample rate, format,
+# etc).
+#allow-moves = false
+
+##
## ALSA backend stuff
##
[alsa]
@@ -270,6 +305,19 @@
#device = /dev/audio
##
+## QSA backend stuff
+##
+[qsa]
+
+## device:
+# Sets the device name for the default playback device.
+#device = default
+
+## capture:
+# Sets the device name for the default capture device.
+#capture = default
+
+##
## MMDevApi backend stuff
##
[mmdevapi]
@@ -300,23 +348,6 @@
#capture = -1
##
-## PulseAudio backend stuff
-##
-[pulse]
-
-## spawn-server:
-# Attempts to spawn a PulseAudio server when requesting to open a PulseAudio
-# device. Setting autospawn to false in PulseAudio's client.conf will still
-# prevent autospawning even if this is set to true.
-#spawn-server = true
-
-## allow-moves:
-# Allows PulseAudio to move active streams to different devices. Note that the
-# device specifier seen by applications will not be updated when this occurs,
-# and neither will the AL device configuration (sample rate, format, etc).
-#allow-moves = false
-
-##
## Wave File Writer stuff
##
[wave]
diff --git a/cmake/CheckCCompilerFlag.cmake b/cmake/CheckCCompilerFlag.cmake
deleted file mode 100644
index 8b2361aa..00000000
--- a/cmake/CheckCCompilerFlag.cmake
+++ /dev/null
@@ -1,59 +0,0 @@
-# - Check if the C source code provided in the SOURCE argument compiles.
-# CHECK_C_SOURCE_COMPILES(SOURCE VAR)
-#
-# FLAG - compiler flag to check
-# VAR - variable to store whether the source code compiled
-#
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-MACRO(CHECK_C_COMPILER_FLAG FLAG VAR)
- IF("${VAR}" MATCHES "^${VAR}$")
- SET(MACRO_CHECK_FUNCTION_DEFINITIONS
- "${FLAG} ${CMAKE_REQUIRED_FLAGS}")
- IF(CMAKE_REQUIRED_LIBRARIES)
- SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- ELSE(CMAKE_REQUIRED_LIBRARIES)
- SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES)
- ENDIF(CMAKE_REQUIRED_LIBRARIES)
- IF(CMAKE_REQUIRED_INCLUDES)
- SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES
- "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
- ELSE(CMAKE_REQUIRED_INCLUDES)
- SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES)
- ENDIF(CMAKE_REQUIRED_INCLUDES)
- FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
- "int main() {return 0;}\n")
-
- MESSAGE(STATUS "Checking if C compiler supports ${FLAG}")
- TRY_COMPILE(${VAR}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- "${CHECK_C_COMPILER_FLAG_ADD_LIBRARIES}"
- "${CHECK_C_COMPILER_FLAG_ADD_INCLUDES}"
- OUTPUT_VARIABLE OUTPUT)
- IF(${VAR})
- SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
- MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Success")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${SOURCE}\n")
- ELSE(${VAR})
- MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Failed")
- SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${SOURCE}\n")
- ENDIF(${VAR})
- ENDIF("${VAR}" MATCHES "^${VAR}$")
-ENDMACRO(CHECK_C_COMPILER_FLAG)
diff --git a/cmake/FindFluidSynth.cmake b/cmake/FindFluidSynth.cmake
new file mode 100644
index 00000000..7d5cb6a8
--- /dev/null
+++ b/cmake/FindFluidSynth.cmake
@@ -0,0 +1,23 @@
+# - Find fluidsynth
+# Find the native fluidsynth includes and library
+#
+# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
+# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
+# FLUIDSYNTH_FOUND - True if fluidsynth found.
+
+
+IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
+ # Already in cache, be silent
+ SET(FluidSynth_FIND_QUIETLY TRUE)
+ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
+
+FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
+
+FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
+MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
+
+# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
+
diff --git a/cmake/FindSDL_sound.cmake b/cmake/FindSDL_sound.cmake
new file mode 100644
index 00000000..97d2a84c
--- /dev/null
+++ b/cmake/FindSDL_sound.cmake
@@ -0,0 +1,382 @@
+# - Locates the SDL_sound library
+#
+# This module depends on SDL being found and
+# must be called AFTER FindSDL.cmake is called.
+#
+# This module defines
+# SDL_SOUND_INCLUDE_DIR, where to find SDL_sound.h
+# SDL_SOUND_FOUND, if false, do not try to link to SDL_sound
+# SDL_SOUND_LIBRARIES, this contains the list of libraries that you need
+# to link against. This is a read-only variable and is marked INTERNAL.
+# SDL_SOUND_EXTRAS, this is an optional variable for you to add your own
+# flags to SDL_SOUND_LIBRARIES. This is prepended to SDL_SOUND_LIBRARIES.
+# This is available mostly for cases this module failed to anticipate for
+# and you must add additional flags. This is marked as ADVANCED.
+# SDL_SOUND_VERSION_STRING, human-readable string containing the version of SDL_sound
+#
+# This module also defines (but you shouldn't need to use directly)
+# SDL_SOUND_LIBRARY, the name of just the SDL_sound library you would link
+# against. Use SDL_SOUND_LIBRARIES for you link instructions and not this one.
+# And might define the following as needed
+# MIKMOD_LIBRARY
+# MODPLUG_LIBRARY
+# OGG_LIBRARY
+# VORBIS_LIBRARY
+# SMPEG_LIBRARY
+# FLAC_LIBRARY
+# SPEEX_LIBRARY
+#
+# Typically, you should not use these variables directly, and you should use
+# SDL_SOUND_LIBRARIES which contains SDL_SOUND_LIBRARY and the other audio libraries
+# (if needed) to successfully compile on your system.
+#
+# Created by Eric Wing.
+# This module is a bit more complicated than the other FindSDL* family modules.
+# The reason is that SDL_sound can be compiled in a large variety of different ways
+# which are independent of platform. SDL_sound may dynamically link against other 3rd
+# party libraries to get additional codec support, such as Ogg Vorbis, SMPEG, ModPlug,
+# MikMod, FLAC, Speex, and potentially others.
+# Under some circumstances which I don't fully understand,
+# there seems to be a requirement
+# that dependent libraries of libraries you use must also be explicitly
+# linked against in order to successfully compile. SDL_sound does not currently
+# have any system in place to know how it was compiled.
+# So this CMake module does the hard work in trying to discover which 3rd party
+# libraries are required for building (if any).
+# This module uses a brute force approach to create a test program that uses SDL_sound,
+# and then tries to build it. If the build fails, it parses the error output for
+# known symbol names to figure out which libraries are needed.
+#
+# Responds to the $SDLDIR and $SDLSOUNDDIR environmental variable that would
+# correspond to the ./configure --prefix=$SDLDIR used in building SDL.
+#
+# On OSX, this will prefer the Framework version (if found) over others.
+# People will have to manually change the cache values of
+# SDL_LIBRARY to override this selectionor set the CMake environment
+# CMAKE_INCLUDE_PATH to modify the search paths.
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+# Copyright 2012 Benjamin Eikel
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+set(SDL_SOUND_EXTRAS "" CACHE STRING "SDL_sound extra flags")
+mark_as_advanced(SDL_SOUND_EXTRAS)
+
+# Find SDL_sound.h
+find_path(SDL_SOUND_INCLUDE_DIR SDL_sound.h
+ HINTS
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ PATH_SUFFIXES SDL SDL12 SDL11
+ )
+
+find_library(SDL_SOUND_LIBRARY
+ NAMES SDL_sound
+ HINTS
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ )
+
+if(SDL_FOUND AND SDL_SOUND_INCLUDE_DIR AND SDL_SOUND_LIBRARY)
+
+ # CMake is giving me problems using TRY_COMPILE with the CMAKE_FLAGS
+ # for the :STRING syntax if I have multiple values contained in a
+ # single variable. This is a problem for the SDL_LIBRARY variable
+ # because it does just that. When I feed this variable to the command,
+ # only the first value gets the appropriate modifier (e.g. -I) and
+ # the rest get dropped.
+ # To get multiple single variables to work, I must separate them with a "\;"
+ # I could go back and modify the FindSDL.cmake module, but that's kind of painful.
+ # The solution would be to try something like:
+ # set(SDL_TRY_COMPILE_LIBRARY_LIST "${SDL_TRY_COMPILE_LIBRARY_LIST}\;${CMAKE_THREAD_LIBS_INIT}")
+ # Instead, it was suggested on the mailing list to write a temporary CMakeLists.txt
+ # with a temporary test project and invoke that with TRY_COMPILE.
+ # See message thread "Figuring out dependencies for a library in order to build"
+ # 2005-07-16
+ # try_compile(
+ # MY_RESULT
+ # ${CMAKE_BINARY_DIR}
+ # ${PROJECT_SOURCE_DIR}/DetermineSoundLibs.c
+ # CMAKE_FLAGS
+ # -DINCLUDE_DIRECTORIES:STRING=${SDL_INCLUDE_DIR}\;${SDL_SOUND_INCLUDE_DIR}
+ # -DLINK_LIBRARIES:STRING=${SDL_SOUND_LIBRARY}\;${SDL_LIBRARY}
+ # OUTPUT_VARIABLE MY_OUTPUT
+ # )
+
+ # To minimize external dependencies, create a sdlsound test program
+ # which will be used to figure out if additional link dependencies are
+ # required for the link phase.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/DetermineSoundLibs.c
+ "#include \"SDL_sound.h\"
+ #include \"SDL.h\"
+ int main(int argc, char* argv[])
+ {
+ Sound_AudioInfo desired;
+ Sound_Sample* sample;
+
+ SDL_Init(0);
+ Sound_Init();
+
+ /* This doesn't actually have to work, but Init() is a no-op
+ * for some of the decoders, so this should force more symbols
+ * to be pulled in.
+ */
+ sample = Sound_NewSampleFromFile(argv[1], &desired, 4096);
+
+ Sound_Quit();
+ SDL_Quit();
+ return 0;
+ }"
+ )
+
+ # Calling
+ # target_link_libraries(DetermineSoundLibs "${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ # causes problems when SDL_LIBRARY looks like
+ # /Library/Frameworks/SDL.framework;-framework Cocoa
+ # The ;-framework Cocoa seems to be confusing CMake once the OS X
+ # framework support was added. I was told that breaking up the list
+ # would fix the problem.
+ set(TMP_TRY_LIBS)
+ foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
+ set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
+ endforeach()
+
+ # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
+
+ # Write the CMakeLists.txt and test project
+ # Weird, this is still sketchy. If I don't quote the variables
+ # in the TARGET_LINK_LIBRARIES, I seem to loose everything
+ # in the SDL_LIBRARY string after the "-framework".
+ # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
+ "cmake_minimum_required(VERSION 2.8)
+ project(DetermineSoundLibs C)
+ include_directories(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
+ add_executable(DetermineSoundLibs DetermineSoundLibs.c)
+ target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
+ )
+
+ try_compile(
+ MY_RESULT
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ DetermineSoundLibs
+ OUTPUT_VARIABLE MY_OUTPUT
+ )
+
+ # message("${MY_RESULT}")
+ # message(${MY_OUTPUT})
+
+ if(NOT MY_RESULT)
+
+ # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
+ # I think Timidity is also compiled in statically.
+ # I've never had to explcitly link against Quicktime, so I'll skip that for now.
+
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
+
+ # Find MikMod
+ if("${MY_OUTPUT}" MATCHES "MikMod_")
+ find_library(MIKMOD_LIBRARY
+ NAMES libmikmod-coreaudio mikmod
+ PATHS
+ ENV MIKMODDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MIKMOD_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
+ endif(MIKMOD_LIBRARY)
+ endif("${MY_OUTPUT}" MATCHES "MikMod_")
+
+ # Find ModPlug
+ if("${MY_OUTPUT}" MATCHES "MODPLUG_")
+ find_library(MODPLUG_LIBRARY
+ NAMES modplug
+ PATHS
+ ENV MODPLUGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(MODPLUG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find Ogg and Vorbis
+ if("${MY_OUTPUT}" MATCHES "ov_")
+ find_library(VORBIS_LIBRARY
+ NAMES vorbis Vorbis VORBIS
+ PATHS
+ ENV VORBISDIR
+ ENV OGGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(VORBIS_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
+ endif()
+
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find SMPEG
+ if("${MY_OUTPUT}" MATCHES "SMPEG_")
+ find_library(SMPEG_LIBRARY
+ NAMES smpeg SMPEG Smpeg SMpeg
+ PATHS
+ ENV SMPEGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SMPEG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
+ endif()
+ endif()
+
+
+ # Find FLAC
+ if("${MY_OUTPUT}" MATCHES "FLAC_")
+ find_library(FLAC_LIBRARY
+ NAMES flac FLAC
+ PATHS
+ ENV FLACDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(FLAC_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+ endif()
+ endif()
+
+
+ # Hmmm...Speex seems to depend on Ogg. This might be a problem if
+ # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
+ # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
+ # above for here or if two ogg entries will screw up things.
+ if("${MY_OUTPUT}" MATCHES "speex_")
+ find_library(SPEEX_LIBRARY
+ NAMES speex SPEEX
+ PATHS
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES
+ lib
+ )
+ if(SPEEX_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+ endif()
+
+ # Find OGG (needed for Speex)
+ # We might have already found Ogg for Vorbis, so skip it if so.
+ if(NOT OGG_LIBRARY)
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ endif()
+ endif()
+ endif()
+
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
+ else()
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY} CACHE INTERNAL "SDL_sound and dependent libraries")
+ endif()
+endif()
+
+if(SDL_SOUND_INCLUDE_DIR AND EXISTS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SOUND_VER_MAJOR[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MINOR_LINE REGEX "^#define[ \t]+SOUND_VER_MINOR[ \t]+[0-9]+$")
+ file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_PATCH_LINE REGEX "^#define[ \t]+SOUND_VER_PATCH[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MAJOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MAJOR "${SDL_SOUND_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MINOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MINOR "${SDL_SOUND_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SOUND_VER_PATCH[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_PATCH "${SDL_SOUND_VERSION_PATCH_LINE}")
+ set(SDL_SOUND_VERSION_STRING ${SDL_SOUND_VERSION_MAJOR}.${SDL_SOUND_VERSION_MINOR}.${SDL_SOUND_VERSION_PATCH})
+ unset(SDL_SOUND_VERSION_MAJOR_LINE)
+ unset(SDL_SOUND_VERSION_MINOR_LINE)
+ unset(SDL_SOUND_VERSION_PATCH_LINE)
+ unset(SDL_SOUND_VERSION_MAJOR)
+ unset(SDL_SOUND_VERSION_MINOR)
+ unset(SDL_SOUND_VERSION_PATCH)
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_sound
+ REQUIRED_VARS SDL_SOUND_LIBRARY SDL_SOUND_INCLUDE_DIR
+ VERSION_VAR SDL_SOUND_VERSION_STRING)
diff --git a/config.h.in b/config.h.in
index 06c34c81..d9582e74 100644
--- a/config.h.in
+++ b/config.h.in
@@ -5,14 +5,14 @@
/* Define to the library version */
#define ALSOFT_VERSION "${LIB_VERSION}"
+#ifdef IN_IDE_PARSER
+/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
+ * recent versions (at least 4.5.1) do recognize GCC's __restrict. */
+#define restrict __restrict
+#endif
+
/* Define any available alignment declaration */
#define ALIGN(x) ${ALIGN_DECL}
-#ifdef __MINGW32__
-#define align(x) aligned(x)
-#endif
-
-/* Define to the appropriate 'restrict' keyword */
-#define RESTRICT ${RESTRICT_DECL}
/* Define if we have the C11 aligned_alloc function */
#cmakedefine HAVE_ALIGNED_ALLOC
@@ -29,6 +29,9 @@
/* Define if we have ARM Neon CPU extensions */
#cmakedefine HAVE_NEON
+/* Define if we have FluidSynth support */
+#cmakedefine HAVE_FLUIDSYNTH
+
/* Define if we have the ALSA backend */
#cmakedefine HAVE_ALSA
@@ -41,6 +44,9 @@
/* Define if we have the SndIO backend */
#cmakedefine HAVE_SNDIO
+/* Define if we have the QSA backend */
+#cmakedefine HAVE_QSA
+
/* Define if we have the MMDevApi backend */
#cmakedefine HAVE_MMDEVAPI
@@ -110,9 +116,15 @@
/* Define if we have malloc.h */
#cmakedefine HAVE_MALLOC_H
+/* Define if we have strings.h */
+#cmakedefine HAVE_STRINGS_H
+
/* Define if we have cpuid.h */
#cmakedefine HAVE_CPUID_H
+/* Define if we have sys/sysconf.h */
+#cmakedefine HAVE_SYS_SYSCONF_H
+
/* Define if we have guiddef.h */
#cmakedefine HAVE_GUIDDEF_H
@@ -128,9 +140,6 @@
/* Define if we have fenv.h */
#cmakedefine HAVE_FENV_H
-/* Define if we have fesetround() */
-#cmakedefine HAVE_FESETROUND
-
/* Define if we have _controlfp() */
#cmakedefine HAVE__CONTROLFP
@@ -139,3 +148,9 @@
/* Define if we have pthread_setschedparam() */
#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
+
+/* Define if we have pthread_setname_np() */
+#cmakedefine HAVE_PTHREAD_SETNAME_NP
+
+/* Define if we have pthread_set_name_np() */
+#cmakedefine HAVE_PTHREAD_SET_NAME_NP
diff --git a/examples/allatency.c b/examples/allatency.c
index 48bf5b51..deb13d3b 100644
--- a/examples/allatency.c
+++ b/examples/allatency.c
@@ -26,37 +26,30 @@
#include <stdio.h>
#include <assert.h>
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <unistd.h>
-#define Sleep(x) usleep((x)*1000)
-#endif
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "common/alhelpers.h"
-#include "common/alffmpeg.h"
+#include "common/sdl_sound.h"
-LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
-LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
+static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
+static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
-LPALSOURCEDSOFT alSourcedSOFT;
-LPALSOURCE3DSOFT alSource3dSOFT;
-LPALSOURCEDVSOFT alSourcedvSOFT;
-LPALGETSOURCEDSOFT alGetSourcedSOFT;
-LPALGETSOURCE3DSOFT alGetSource3dSOFT;
-LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
-LPALSOURCEI64SOFT alSourcei64SOFT;
-LPALSOURCE3I64SOFT alSource3i64SOFT;
-LPALSOURCEI64VSOFT alSourcei64vSOFT;
-LPALGETSOURCEI64SOFT alGetSourcei64SOFT;
-LPALGETSOURCE3I64SOFT alGetSource3i64SOFT;
-LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
+static LPALSOURCEDSOFT alSourcedSOFT;
+static LPALSOURCE3DSOFT alSource3dSOFT;
+static LPALSOURCEDVSOFT alSourcedvSOFT;
+static LPALGETSOURCEDSOFT alGetSourcedSOFT;
+static LPALGETSOURCE3DSOFT alGetSource3dSOFT;
+static LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
+static LPALSOURCEI64SOFT alSourcei64SOFT;
+static LPALSOURCE3I64SOFT alSource3i64SOFT;
+static LPALSOURCEI64VSOFT alSourcei64vSOFT;
+static LPALGETSOURCEI64SOFT alGetSourcei64SOFT;
+static LPALGETSOURCE3I64SOFT alGetSource3i64SOFT;
+static LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
* returns the new buffer ID. */
@@ -66,24 +59,22 @@ static ALuint LoadSound(const char *filename)
ALuint rate, buffer;
size_t datalen;
void *data;
- FilePtr audiofile;
- StreamPtr sound;
+ FilePtr sound;
- /* Open the file and get the first stream from it */
- audiofile = openAVFile(filename);
- sound = getAVAudioStream(audiofile, 0);
+ /* Open the audio file */
+ sound = openAudioFile(filename, 1000);
if(!sound)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
/* Get the sound format, and figure out the OpenAL format */
- if(getAVAudioInfo(sound, &rate, &channels, &type) != 0)
+ if(getAudioInfo(sound, &rate, &channels, &type) != 0)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
@@ -92,16 +83,16 @@ static ALuint LoadSound(const char *filename)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(channels), TypeName(type), filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
/* Decode the whole audio stream to a buffer. */
- data = decodeAVAudioStream(sound, &datalen);
+ data = decodeAudioStream(sound, &datalen);
if(!data)
{
fprintf(stderr, "Failed to read audio from %s\n", filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
@@ -112,7 +103,7 @@ static ALuint LoadSound(const char *filename)
alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type),
channels, type, data);
free(data);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
/* Check if an error occured, and clean up if so. */
err = alGetError();
diff --git a/examples/alloopback.c b/examples/alloopback.c
new file mode 100644
index 00000000..649ef6ef
--- /dev/null
+++ b/examples/alloopback.c
@@ -0,0 +1,244 @@
+/*
+ * OpenAL Loopback Example
+ *
+ * Copyright (c) 2013 by Chris Robinson <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This file contains an example for using the loopback device for custom
+ * output handling.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include <SDL.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "common/alhelpers.h"
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+typedef struct {
+ ALCdevice *Device;
+ ALCcontext *Context;
+
+ ALCsizei FrameSize;
+} PlaybackInfo;
+
+static LPALCLOOPBACKOPENDEVICESOFT alcLoopbackOpenDeviceSOFT;
+static LPALCISRENDERFORMATSUPPORTEDSOFT alcIsRenderFormatSupportedSOFT;
+static LPALCRENDERSAMPLESSOFT alcRenderSamplesSOFT;
+
+
+void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len)
+{
+ PlaybackInfo *playback = (PlaybackInfo*)userdata;
+ alcRenderSamplesSOFT(playback->Device, stream, len/playback->FrameSize);
+}
+
+
+/* Creates a one second buffer containing a sine wave, and returns the new
+ * buffer ID. */
+static ALuint CreateSineWave(void)
+{
+ ALshort data[44100];
+ ALuint buffer;
+ ALenum err;
+ ALuint i;
+
+ for(i = 0;i < 44100;i++)
+ data[i] = (ALshort)(sin(i * 441.0 / 44100.0 * 2.0*M_PI)*32767.0);
+
+ /* Buffer the audio data into a new buffer object. */
+ buffer = 0;
+ alGenBuffers(1, &buffer);
+ alBufferData(buffer, AL_FORMAT_MONO16, data, sizeof(data), 44100);
+
+ /* Check if an error occured, and clean up if so. */
+ err = alGetError();
+ if(err != AL_NO_ERROR)
+ {
+ fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
+ if(alIsBuffer(buffer))
+ alDeleteBuffers(1, &buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+
+int main()
+{
+ PlaybackInfo playback = { NULL, NULL, 0 };
+ SDL_AudioSpec desired, obtained;
+ ALuint source, buffer;
+ ALCint attrs[16];
+ ALenum state;
+
+ /* Print out error if extension is missing. */
+ if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback"))
+ {
+ fprintf(stderr, "Error: ALC_SOFT_loopback not supported!\n");
+ return 1;
+ }
+
+ /* Define a macro to help load the function pointers. */
+#define LOAD_PROC(x) ((x) = alcGetProcAddress(NULL, #x))
+ LOAD_PROC(alcLoopbackOpenDeviceSOFT);
+ LOAD_PROC(alcIsRenderFormatSupportedSOFT);
+ LOAD_PROC(alcRenderSamplesSOFT);
+#undef LOAD_PROC
+
+ if(SDL_Init(SDL_INIT_AUDIO) == -1)
+ {
+ fprintf(stderr, "Failed to init SDL audio: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ /* Set up SDL audio with our requested format and callback. */
+ desired.channels = 2;
+ desired.format = AUDIO_S16SYS;
+ desired.freq = 44100;
+ desired.padding = 0;
+ desired.samples = 4096;
+ desired.callback = RenderSDLSamples;
+ desired.userdata = &playback;
+ if(SDL_OpenAudio(&desired, &obtained) != 0)
+ {
+ SDL_Quit();
+ fprintf(stderr, "Failed to open SDL audio: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ /* Set up our OpenAL attributes based on what we got from SDL. */
+ attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
+ if(obtained.channels == 1)
+ attrs[1] = ALC_MONO_SOFT;
+ else if(obtained.channels == 2)
+ attrs[1] = ALC_STEREO_SOFT;
+ else
+ {
+ fprintf(stderr, "Unhandled SDL channel count: %d\n", obtained.channels);
+ goto error;
+ }
+
+ attrs[2] = ALC_FORMAT_TYPE_SOFT;
+ if(obtained.format == AUDIO_U8)
+ attrs[3] = ALC_UNSIGNED_BYTE_SOFT;
+ else if(obtained.format == AUDIO_S8)
+ attrs[3] = ALC_BYTE_SOFT;
+ else if(obtained.format == AUDIO_U16SYS)
+ attrs[3] = ALC_UNSIGNED_SHORT_SOFT;
+ else if(obtained.format == AUDIO_S16SYS)
+ attrs[3] = ALC_SHORT_SOFT;
+ else
+ {
+ fprintf(stderr, "Unhandled SDL format: 0x%04x\n", obtained.format);
+ goto error;
+ }
+
+ attrs[4] = ALC_FREQUENCY;
+ attrs[5] = obtained.freq;
+
+ attrs[6] = 0; /* end of list */
+
+ /* Initialize OpenAL loopback device, using our format attributes. */
+ playback.Device = alcLoopbackOpenDeviceSOFT(NULL);
+ if(!playback.Device)
+ {
+ fprintf(stderr, "Failed to open loopback device!\n");
+ goto error;
+ }
+ /* Make sure the format is supported before setting them on the device. */
+ if(alcIsRenderFormatSupportedSOFT(playback.Device, attrs[5], attrs[1], attrs[3]) == ALC_FALSE)
+ {
+ fprintf(stderr, "Render format not supported: %s, %s, %dhz\n",
+ ChannelsName(attrs[1]), TypeName(attrs[3]), attrs[5]);
+ goto error;
+ }
+ playback.Context = alcCreateContext(playback.Device, attrs);
+ if(!playback.Context || alcMakeContextCurrent(playback.Context) == ALC_FALSE)
+ {
+ fprintf(stderr, "Failed to set an OpenAL audio context\n");
+ goto error;
+ }
+ playback.FrameSize = FramesToBytes(1, attrs[1], attrs[3]);
+
+ /* Start SDL playing. Our callback (thus alcRenderSamplesSOFT) will now
+ * start being called regularly to update the AL playback state. */
+ SDL_PauseAudio(0);
+
+ /* Load the sound into a buffer. */
+ buffer = CreateSineWave();
+ if(!buffer)
+ {
+ SDL_CloseAudio();
+ alcDestroyContext(playback.Context);
+ alcCloseDevice(playback.Device);
+ SDL_Quit();
+ return 1;
+ }
+
+ /* Create the source to play the sound with. */
+ source = 0;
+ alGenSources(1, &source);
+ alSourcei(source, AL_BUFFER, buffer);
+ assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source");
+
+ /* Play the sound until it finishes. */
+ alSourcePlay(source);
+ do {
+ Sleep(10);
+ alGetSourcei(source, AL_SOURCE_STATE, &state);
+ } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
+
+ /* All done. Delete resources, and close OpenAL. */
+ alDeleteSources(1, &source);
+ alDeleteBuffers(1, &buffer);
+
+ /* Stop SDL playing. */
+ SDL_PauseAudio(1);
+
+ /* Close up OpenAL and SDL. */
+ SDL_CloseAudio();
+ alcDestroyContext(playback.Context);
+ alcCloseDevice(playback.Device);
+ SDL_Quit();
+
+ return 0;
+
+error:
+ SDL_CloseAudio();
+ if(playback.Context)
+ alcDestroyContext(playback.Context);
+ if(playback.Device)
+ alcCloseDevice(playback.Device);
+ SDL_Quit();
+
+ return 1;
+}
diff --git a/examples/alreverb.c b/examples/alreverb.c
index 5001740e..420b1c55 100644
--- a/examples/alreverb.c
+++ b/examples/alreverb.c
@@ -26,13 +26,6 @@
#include <stdio.h>
#include <assert.h>
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <unistd.h>
-#define Sleep(x) usleep((x)*1000)
-#endif
#include "AL/al.h"
#include "AL/alc.h"
@@ -40,37 +33,37 @@
#include "AL/efx-presets.h"
#include "common/alhelpers.h"
-#include "common/alffmpeg.h"
+#include "common/sdl_sound.h"
-LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
-LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
+static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
+static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
/* Effect object functions */
-LPALGENEFFECTS alGenEffects;
-LPALDELETEEFFECTS alDeleteEffects;
-LPALISEFFECT alIsEffect;
-LPALEFFECTI alEffecti;
-LPALEFFECTIV alEffectiv;
-LPALEFFECTF alEffectf;
-LPALEFFECTFV alEffectfv;
-LPALGETEFFECTI alGetEffecti;
-LPALGETEFFECTIV alGetEffectiv;
-LPALGETEFFECTF alGetEffectf;
-LPALGETEFFECTFV alGetEffectfv;
+static LPALGENEFFECTS alGenEffects;
+static LPALDELETEEFFECTS alDeleteEffects;
+static LPALISEFFECT alIsEffect;
+static LPALEFFECTI alEffecti;
+static LPALEFFECTIV alEffectiv;
+static LPALEFFECTF alEffectf;
+static LPALEFFECTFV alEffectfv;
+static LPALGETEFFECTI alGetEffecti;
+static LPALGETEFFECTIV alGetEffectiv;
+static LPALGETEFFECTF alGetEffectf;
+static LPALGETEFFECTFV alGetEffectfv;
/* Auxiliary Effect Slot object functions */
-LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
-LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
-LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
-LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
-LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
-LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
-LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
-LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
-LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
-LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
-LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
+static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
+static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
+static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
+static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
+static LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
+static LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
+static LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
+static LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
+static LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
+static LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
+static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
/* LoadEffect loads the given reverb properties into a new OpenAL effect
@@ -159,24 +152,21 @@ static ALuint LoadSound(const char *filename)
ALuint rate, buffer;
size_t datalen;
void *data;
- FilePtr audiofile;
- StreamPtr sound;
+ FilePtr sound;
/* Open the file and get the first stream from it */
- audiofile = openAVFile(filename);
- sound = getAVAudioStream(audiofile, 0);
+ sound = openAudioFile(filename, 1000);
if(!sound)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
- closeAVFile(audiofile);
return 0;
}
/* Get the sound format, and figure out the OpenAL format */
- if(getAVAudioInfo(sound, &rate, &channels, &type) != 0)
+ if(getAudioInfo(sound, &rate, &channels, &type) != 0)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
@@ -185,16 +175,16 @@ static ALuint LoadSound(const char *filename)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(channels), TypeName(type), filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
/* Decode the whole audio stream to a buffer. */
- data = decodeAVAudioStream(sound, &datalen);
+ data = decodeAudioStream(sound, &datalen);
if(!data)
{
fprintf(stderr, "Failed to read audio from %s\n", filename);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
return 0;
}
@@ -205,7 +195,7 @@ static ALuint LoadSound(const char *filename)
alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type),
channels, type, data);
free(data);
- closeAVFile(audiofile);
+ closeAudioFile(sound);
/* Check if an error occured, and clean up if so. */
err = alGetError();
diff --git a/examples/alstream.c b/examples/alstream.c
index 121cec00..2972d375 100644
--- a/examples/alstream.c
+++ b/examples/alstream.c
@@ -35,32 +35,26 @@
#include "AL/alext.h"
#include "common/alhelpers.h"
-#include "common/alffmpeg.h"
+#include "common/sdl_sound.h"
-LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
-LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT = NULL;
+static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples;
+static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT;
-/* Define the number of buffers and buffer size (in samples) to use. 4 buffers
- * with 8192 samples each gives a nice per-chunk size, and lets the queue last
- * for almost 3/4ths of a second for a 44.1khz stream. */
+/* Define the number of buffers and buffer size (in milliseconds) to use. 4
+ * buffers with 200ms each gives a nice per-chunk size, and lets the queue last
+ * for almost one second. */
#define NUM_BUFFERS 4
-#define BUFFER_SIZE 8192
+#define BUFFER_TIME_MS 200
typedef struct StreamPlayer {
/* These are the buffers and source to play out through OpenAL with */
ALuint buffers[NUM_BUFFERS];
ALuint source;
- /* Handles for the audio stream */
+ /* Handle for the audio file */
FilePtr file;
- StreamPtr stream;
-
- /* A temporary data buffer for readAVAudioData to write to and pass to
- * OpenAL with */
- ALbyte *data;
- ALsizei datasize;
/* The format of the output stream */
ALenum format;
@@ -128,17 +122,15 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename)
ClosePlayerFile(player);
/* Open the file and get the first stream from it */
- player->file = openAVFile(filename);
- player->stream = getAVAudioStream(player->file, 0);
- if(!player->stream)
+ player->file = openAudioFile(filename, BUFFER_TIME_MS);
+ if(!player->file)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
goto error;
}
/* Get the stream format, and figure out the OpenAL format */
- if(getAVAudioInfo(player->stream, &player->rate, &player->channels,
- &player->type) != 0)
+ if(getAudioInfo(player->file, &player->rate, &player->channels, &player->type) != 0)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
goto error;
@@ -153,23 +145,11 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename)
goto error;
}
- /* Allocate enough space for the temp buffer, given the format */
- player->datasize = FramesToBytes(BUFFER_SIZE, player->channels,
- player->type);
- player->data = malloc(player->datasize);
- if(player->data == NULL)
- {
- fprintf(stderr, "Error allocating %d bytes\n", player->datasize);
- goto error;
- }
-
return 1;
error:
- closeAVFile(player->file);
+ closeAudioFile(player->file);
player->file = NULL;
- player->stream = NULL;
- player->datasize = 0;
return 0;
}
@@ -177,20 +157,15 @@ error:
/* Closes the audio file stream */
static void ClosePlayerFile(StreamPlayer *player)
{
- closeAVFile(player->file);
+ closeAudioFile(player->file);
player->file = NULL;
- player->stream = NULL;
-
- free(player->data);
- player->data = NULL;
- player->datasize = 0;
}
/* Prebuffers some audio from the file, and starts playing the source */
static int StartPlayer(StreamPlayer *player)
{
- size_t i, got;
+ size_t i;
/* Rewind the source position and clear the buffer queue */
alSourceRewind(player->source);
@@ -199,13 +174,16 @@ static int StartPlayer(StreamPlayer *player)
/* Fill the buffer queue */
for(i = 0;i < NUM_BUFFERS;i++)
{
+ uint8_t *data;
+ size_t got;
+
/* Get some data to give it to the buffer */
- got = readAVAudioData(player->stream, player->data, player->datasize);
- if(got == 0) break;
+ data = getAudioData(player->file, &got);
+ if(!data) break;
alBufferSamplesSOFT(player->buffers[i], player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
- player->channels, player->type, player->data);
+ player->channels, player->type, data);
}
if(alGetError() != AL_NO_ERROR)
{
@@ -242,6 +220,7 @@ static int UpdatePlayer(StreamPlayer *player)
while(processed > 0)
{
ALuint bufid;
+ uint8_t *data;
size_t got;
alSourceUnqueueBuffers(player->source, 1, &bufid);
@@ -249,12 +228,12 @@ static int UpdatePlayer(StreamPlayer *player)
/* Read the next chunk of data, refill the buffer, and queue it
* back on the source */
- got = readAVAudioData(player->stream, player->data, player->datasize);
- if(got > 0)
+ data = getAudioData(player->file, &got);
+ if(data != NULL)
{
alBufferSamplesSOFT(bufid, player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
- player->channels, player->type, player->data);
+ player->channels, player->type, data);
alSourceQueueBuffers(player->source, 1, &bufid);
}
if(alGetError() != AL_NO_ERROR)
@@ -315,10 +294,19 @@ int main(int argc, char **argv)
/* Play each file listed on the command line */
for(i = 1;i < argc;i++)
{
+ const char *namepart;
+
if(!OpenPlayerFile(player, argv[i]))
continue;
- printf("Playing %s (%s, %s, %dhz)\n", argv[i],
+ /* Get the name portion, without the path, for display. */
+ namepart = strrchr(argv[i], '/');
+ if(namepart || (namepart=strrchr(argv[i], '\\')))
+ namepart++;
+ else
+ namepart = argv[i];
+
+ printf("Playing: %s (%s, %s, %dhz)\n", namepart,
TypeName(player->type), ChannelsName(player->channels),
player->rate);
fflush(stdout);
diff --git a/examples/common/alffmpeg.c b/examples/common/alffmpeg.c
deleted file mode 100644
index 16f73866..00000000
--- a/examples/common/alffmpeg.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * FFmpeg Decoder Helpers
- *
- * Copyright (c) 2011 by Chris Robinson <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* This file contains routines for helping to decode audio using libavformat
- * and libavcodec (ffmpeg). There's very little OpenAL-specific code here. */
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "AL/al.h"
-#include "AL/alc.h"
-#include "AL/alext.h"
-
-#include "alhelpers.h"
-#include "alffmpeg.h"
-
-
-static size_t NextPowerOf2(size_t value)
-{
- size_t powerOf2 = 1;
-
- if(value)
- {
- value--;
- while(value)
- {
- value >>= 1;
- powerOf2 <<= 1;
- }
- }
- return powerOf2;
-}
-
-
-struct MemData {
- char *buffer;
- size_t length;
- size_t pos;
-};
-
-static int MemData_read(void *opaque, uint8_t *buf, int buf_size)
-{
- struct MemData *membuf = (struct MemData*)opaque;
- int rem = membuf->length - membuf->pos;
-
- if(rem > buf_size)
- rem = buf_size;
-
- memcpy(buf, &membuf->buffer[membuf->pos], rem);
- membuf->pos += rem;
-
- return rem;
-}
-
-static int MemData_write(void *opaque, uint8_t *buf, int buf_size)
-{
- struct MemData *membuf = (struct MemData*)opaque;
- int rem = membuf->length - membuf->pos;
-
- if(rem > buf_size)
- rem = buf_size;
-
- memcpy(&membuf->buffer[membuf->pos], buf, rem);
- membuf->pos += rem;
-
- return rem;
-}
-
-static int64_t MemData_seek(void *opaque, int64_t offset, int whence)
-{
- struct MemData *membuf = (struct MemData*)opaque;
-
- whence &= ~AVSEEK_FORCE;
- switch(whence)
- {
- case SEEK_SET:
- if(offset < 0 || (uint64_t)offset > membuf->length)
- return -1;
- membuf->pos = offset;
- break;
-
- case SEEK_CUR:
- if((offset >= 0 && (uint64_t)offset > membuf->length-membuf->pos) ||
- (offset < 0 && (uint64_t)(-offset) > membuf->pos))
- return -1;
- membuf->pos += offset;
- break;
-
- case SEEK_END:
- if(offset > 0 || (uint64_t)(-offset) > membuf->length)
- return -1;
- membuf->pos = membuf->length + offset;
- break;
-
- case AVSEEK_SIZE:
- return membuf->length;
-
- default:
- return -1;
- }
-
- return membuf->pos;
-}
-
-
-struct PacketList {
- AVPacket pkt;
- struct PacketList *next;
-};
-
-struct MyStream {
- AVCodecContext *CodecCtx;
- int StreamIdx;
-
- struct PacketList *Packets;
-
- AVFrame *Frame;
-
- const uint8_t *FrameData;
- size_t FrameDataSize;
-
- FilePtr parent;
-};
-
-struct MyFile {
- AVFormatContext *FmtCtx;
-
- StreamPtr *Streams;
- size_t StreamsSize;
-
- struct MemData membuf;
-};
-
-
-static int done_init = 0;
-
-FilePtr openAVFile(const char *fname)
-{
- FilePtr file;
-
- /* We need to make sure ffmpeg is initialized. Optionally silence warning
- * output from the lib */
- if(!done_init) {av_register_all();
- av_log_set_level(AV_LOG_ERROR);
- done_init = 1;}
-
- file = (FilePtr)calloc(1, sizeof(*file));
- if(file && avformat_open_input(&file->FmtCtx, fname, NULL, NULL) == 0)
- {
- /* After opening, we must search for the stream information because not
- * all formats will have it in stream headers */
- if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
- return file;
- avformat_close_input(&file->FmtCtx);
- }
-
- free(file);
- return NULL;
-}
-
-FilePtr openAVData(const char *name, char *buffer, size_t buffer_len)
-{
- FilePtr file;
-
- if(!done_init) {av_register_all();
- av_log_set_level(AV_LOG_ERROR);
- done_init = 1;}
-
- if(!name)
- name = "";
-
- file = (FilePtr)calloc(1, sizeof(*file));
- if(file && (file->FmtCtx=avformat_alloc_context()) != NULL)
- {
- file->membuf.buffer = buffer;
- file->membuf.length = buffer_len;
- file->membuf.pos = 0;
-
- file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, &file->membuf,
- MemData_read, MemData_write,
- MemData_seek);
- if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0)
- {
- if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
- return file;
- avformat_close_input(&file->FmtCtx);
- }
- if(file->FmtCtx)
- avformat_free_context(file->FmtCtx);
- file->FmtCtx = NULL;
- }
-
- free(file);
- return NULL;
-}
-
-FilePtr openAVCustom(const char *name, void *user_data,
- int (*read_packet)(void *user_data, uint8_t *buf, int buf_size),
- int (*write_packet)(void *user_data, uint8_t *buf, int buf_size),
- int64_t (*seek)(void *user_data, int64_t offset, int whence))
-{
- FilePtr file;
-
- if(!done_init) {av_register_all();
- av_log_set_level(AV_LOG_ERROR);
- done_init = 1;}
-
- if(!name)
- name = "";
-
- file = (FilePtr)calloc(1, sizeof(*file));
- if(file && (file->FmtCtx=avformat_alloc_context()) != NULL)
- {
- file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, user_data,
- read_packet, write_packet, seek);
- if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0)
- {
- if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
- return file;
- avformat_close_input(&file->FmtCtx);
- }
- if(file->FmtCtx)
- avformat_free_context(file->FmtCtx);
- file->FmtCtx = NULL;
- }
-
- free(file);
- return NULL;
-}
-
-
-void clearAVAudioData(StreamPtr stream)
-{
- while(stream->Packets)
- {
- struct PacketList *self;
-
- self = stream->Packets;
- stream->Packets = self->next;
-
- av_free_packet(&self->pkt);
- av_free(self);
- }
-}
-
-
-void closeAVFile(FilePtr file)
-{
- size_t i;
-
- if(!file) return;
-
- for(i = 0;i < file->StreamsSize;i++)
- {
- StreamPtr stream = file->Streams[i];
-
- while(stream->Packets)
- {
- struct PacketList *self;
-
- self = stream->Packets;
- stream->Packets = self->next;
-
- av_free_packet(&self->pkt);
- av_free(self);
- }
-
- avcodec_close(stream->CodecCtx);
- av_free(stream->Frame);
- free(stream);
- }
- free(file->Streams);
-
- avformat_close_input(&file->FmtCtx);
- free(file);
-}
-
-
-int getAVFileInfo(FilePtr file, int *numaudiostreams)
-{
- unsigned int i;
- int audiocount = 0;
-
- if(!file) return 1;
- for(i = 0;i < file->FmtCtx->nb_streams;i++)
- {
- if(file->FmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- audiocount++;
- }
- *numaudiostreams = audiocount;
- return 0;
-}
-
-StreamPtr getAVAudioStream(FilePtr file, int streamnum)
-{
- unsigned int i;
- if(!file) return NULL;
- for(i = 0;i < file->FmtCtx->nb_streams;i++)
- {
- if(file->FmtCtx->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
- continue;
-
- if(streamnum == 0)
- {
- StreamPtr stream;
- AVCodec *codec;
- void *temp;
- size_t j;
-
- /* Found the requested stream. Check if a handle to this stream
- * already exists and return it if it does */
- for(j = 0;j < file->StreamsSize;j++)
- {
- if(file->Streams[j]->StreamIdx == (int)i)
- return file->Streams[j];
- }
-
- /* Doesn't yet exist. Now allocate a new stream object and fill in
- * its info */
- stream = (StreamPtr)calloc(1, sizeof(*stream));
- if(!stream) return NULL;
-
- stream->parent = file;
- stream->CodecCtx = file->FmtCtx->streams[i]->codec;
- stream->StreamIdx = i;
-
- /* Try to find the codec for the given codec ID, and open it */
- codec = avcodec_find_decoder(stream->CodecCtx->codec_id);
- if(!codec || avcodec_open2(stream->CodecCtx, codec, NULL) < 0)
- {
- free(stream);
- return NULL;
- }
-
- /* Allocate space for the decoded data to be stored in before it
- * gets passed to the app */
- stream->Frame = avcodec_alloc_frame();
- if(!stream->Frame)
- {
- avcodec_close(stream->CodecCtx);
- free(stream);
- return NULL;
- }
- stream->FrameData = NULL;
- stream->FrameDataSize = 0;
-
- /* Append the new stream object to the stream list. The original
- * pointer will remain valid if realloc fails, so we need to use
- * another pointer to watch for errors and not leak memory */
- temp = realloc(file->Streams, (file->StreamsSize+1) *
- sizeof(*file->Streams));
- if(!temp)
- {
- avcodec_close(stream->CodecCtx);
- av_free(stream->Frame);
- free(stream);
- return NULL;
- }
- file->Streams = (StreamPtr*)temp;
- file->Streams[file->StreamsSize++] = stream;
- return stream;
- }
- streamnum--;
- }
- return NULL;
-}
-
-int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type)
-{
- if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
- return 1;
-
- /* Get the sample type for OpenAL given the format detected by ffmpeg. */
- if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
- *type = AL_UNSIGNED_BYTE_SOFT;
- else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S16)
- *type = AL_SHORT_SOFT;
- else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S32)
- *type = AL_INT_SOFT;
- else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT)
- *type = AL_FLOAT_SOFT;
- else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_DBL)
- *type = AL_DOUBLE_SOFT;
- else
- {
- fprintf(stderr, "Unsupported ffmpeg sample format: %s\n",
- av_get_sample_fmt_name(stream->CodecCtx->sample_fmt));
- return 1;
- }
-
- /* Get the OpenAL channel configuration using the channel layout detected
- * by ffmpeg. NOTE: some file types may not specify a channel layout. In
- * that case, one must be guessed based on the channel count. */
- if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_MONO)
- *channels = AL_MONO_SOFT;
- else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_STEREO)
- *channels = AL_STEREO_SOFT;
- else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_QUAD)
- *channels = AL_QUAD_SOFT;
- else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK)
- *channels = AL_5POINT1_SOFT;
- else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1)
- *channels = AL_7POINT1_SOFT;
- else if(stream->CodecCtx->channel_layout == 0)
- {
- /* Unknown channel layout. Try to guess. */
- if(stream->CodecCtx->channels == 1)
- *channels = AL_MONO_SOFT;
- else if(stream->CodecCtx->channels == 2)
- *channels = AL_STEREO_SOFT;
- else
- {
- fprintf(stderr, "Unsupported ffmpeg raw channel count: %d\n",
- stream->CodecCtx->channels);
- return 1;
- }
- }
- else
- {
- char str[1024];
- av_get_channel_layout_string(str, sizeof(str), stream->CodecCtx->channels,
- stream->CodecCtx->channel_layout);
- fprintf(stderr, "Unsupported ffmpeg channel layout: %s\n", str);
- return 1;
- }
-
- *rate = stream->CodecCtx->sample_rate;
-
- return 0;
-}
-
-
-/* Used by getAV*Data to search for more compressed data, and buffer it in the
- * correct stream. It won't buffer data for streams that the app doesn't have a
- * handle for. */
-static int getNextPacket(FilePtr file, int streamidx)
-{
- struct PacketList *packet;
-
- packet = (struct PacketList*)av_malloc(sizeof(*packet));
- packet->next = NULL;
-
-next_packet:
- while(av_read_frame(file->FmtCtx, &packet->pkt) >= 0)
- {
- StreamPtr *iter = file->Streams;
- StreamPtr *iter_end = iter + file->StreamsSize;
-
- /* Check each stream the user has a handle for, looking for the one
- * this packet belongs to */
- while(iter != iter_end)
- {
- if((*iter)->StreamIdx == packet->pkt.stream_index)
- {
- struct PacketList **last;
-
- last = &(*iter)->Packets;
- while(*last != NULL)
- last = &(*last)->next;
-
- *last = packet;
- if((*iter)->StreamIdx == streamidx)
- return 1;
-
- packet = (struct PacketList*)av_malloc(sizeof(*packet));
- packet->next = NULL;
- goto next_packet;
- }
- iter++;
- }
- /* Free the packet and look for another */
- av_free_packet(&packet->pkt);
- }
-
- av_free(packet);
- return 0;
-}
-
-uint8_t *getAVAudioData(StreamPtr stream, size_t *length)
-{
- int got_frame;
- int len;
-
- if(length) *length = 0;
-
- if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
- return NULL;
-
-next_packet:
- if(!stream->Packets && !getNextPacket(stream->parent, stream->StreamIdx))
- return NULL;
-
- /* Decode some data, and check for errors */
- avcodec_get_frame_defaults(stream->Frame);
- while((len=avcodec_decode_audio4(stream->CodecCtx, stream->Frame,
- &got_frame, &stream->Packets->pkt)) < 0)
- {
- struct PacketList *self;
-
- /* Error? Drop it and try the next, I guess... */
- self = stream->Packets;
- stream->Packets = self->next;
-
- av_free_packet(&self->pkt);
- av_free(self);
-
- if(!stream->Packets)
- goto next_packet;
- }
-
- if(len < stream->Packets->pkt.size)
- {
- /* Move the unread data to the front and clear the end bits */
- int remaining = stream->Packets->pkt.size - len;
- memmove(stream->Packets->pkt.data, &stream->Packets->pkt.data[len],
- remaining);
- memset(&stream->Packets->pkt.data[remaining], 0,
- stream->Packets->pkt.size - remaining);
- stream->Packets->pkt.size -= len;
- }
- else
- {
- struct PacketList *self;
-
- self = stream->Packets;
- stream->Packets = self->next;
-
- av_free_packet(&self->pkt);
- av_free(self);
- }
-
- if(!got_frame || stream->Frame->nb_samples == 0)
- goto next_packet;
-
- /* Set the output buffer size */
- *length = av_samples_get_buffer_size(NULL, stream->CodecCtx->channels,
- stream->Frame->nb_samples,
- stream->CodecCtx->sample_fmt, 1);
-
- return stream->Frame->data[0];
-}
-
-size_t readAVAudioData(StreamPtr stream, void *data, size_t length)
-{
- size_t dec = 0;
-
- if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
- return 0;
-
- while(dec < length)
- {
- /* If there's no decoded data, find some */
- if(stream->FrameDataSize == 0)
- {
- stream->FrameData = getAVAudioData(stream, &stream->FrameDataSize);
- if(!stream->FrameData)
- break;
- }
-
- if(stream->FrameDataSize > 0)
- {
- /* Get the amount of bytes remaining to be written, and clamp to
- * the amount of decoded data we have */
- size_t rem = length-dec;
- if(rem > stream->FrameDataSize)
- rem = stream->FrameDataSize;
-
- /* Copy the data to the app's buffer and increment */
- if(data != NULL)
- {
- memcpy(data, stream->FrameData, rem);
- data = (char*)data + rem;
- }
- dec += rem;
-
- /* If there's any decoded data left, move it to the front of the
- * buffer for next time */
- stream->FrameData += rem;
- stream->FrameDataSize -= rem;
- }
- }
-
- /* Return the number of bytes we were able to get */
- return dec;
-}
-
-void *decodeAVAudioStream(StreamPtr stream, size_t *length)
-{
- char *outbuf = NULL;
- size_t buflen = 0;
- void *inbuf;
- size_t got;
-
- *length = 0;
- if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
- return NULL;
-
- while((inbuf=getAVAudioData(stream, &got)) != NULL && got > 0)
- {
- void *ptr;
-
- ptr = realloc(outbuf, NextPowerOf2(buflen+got));
- if(ptr == NULL)
- break;
- outbuf = (char*)ptr;
-
- memcpy(&outbuf[buflen], inbuf, got);
- buflen += got;
- }
- outbuf = (char*)realloc(outbuf, buflen);
-
- *length = buflen;
- return outbuf;
-}
diff --git a/examples/common/alffmpeg.h b/examples/common/alffmpeg.h
deleted file mode 100644
index 27e49ab4..00000000
--- a/examples/common/alffmpeg.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef ALFFMPEG_H
-#define ALFFMPEG_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-
-/* Opaque handles to files and streams. Apps don't need to concern themselves
- * with the internals */
-typedef struct MyFile *FilePtr;
-typedef struct MyStream *StreamPtr;
-
-/* Opens a file with ffmpeg and sets up the streams' information */
-FilePtr openAVFile(const char *fname);
-
-/* Opens a named file image with ffmpeg and sets up the streams' information */
-FilePtr openAVData(const char *name, char *buffer, size_t buffer_len);
-
-/* Opens a named data stream with ffmpeg, using the specified data pointer and
- * callbacks, and sets up the streams' information */
-FilePtr openAVCustom(const char *name, void *user_data,
- int (*read_packet)(void *user_data, uint8_t *buf, int buf_size),
- int (*write_packet)(void *user_data, uint8_t *buf, int buf_size),
- int64_t (*seek)(void *user_data, int64_t offset, int whence));
-
-/* Closes/frees an opened file and any of its streams */
-void closeAVFile(FilePtr file);
-
-/* Reports certain information from the file, eg, the number of audio
- * streams. Returns 0 on success. */
-int getAVFileInfo(FilePtr file, int *numaudiostreams);
-
-/* Retrieves a handle for the given audio stream number (generally 0, but some
- * files can have multiple audio streams in one file). */
-StreamPtr getAVAudioStream(FilePtr file, int streamnum);
-
-/* Returns information about the given audio stream. Returns 0 on success. */
-int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type);
-
-/* Returns a pointer to the next available packet of decoded audio. Any data
- * from a previously-decoded packet is dropped. The size (in bytes) of the
- * returned data buffer is stored in 'length', and the returned pointer is only
- * valid until the next call to getAVAudioData or readAVAudioData. */
-uint8_t *getAVAudioData(StreamPtr stream, size_t *length);
-
-/* The "meat" function. Decodes audio and writes, at most, length bytes into
- * the provided data buffer. Will only return less for end-of-stream or error
- * conditions. Returns the number of bytes written. */
-size_t readAVAudioData(StreamPtr stream, void *data, size_t length);
-
-/* Decodes all remaining data from the stream and returns a buffer containing
- * the audio data, with the size stored in 'length'. The returned pointer must
- * be freed with a call to free(). Note that since this decodes the whole
- * stream, using it on lengthy streams (eg, music) will use a lot of memory.
- * Such streams are better handled using getAVAudioData or readAVAudioData to
- * keep smaller chunks in memory at any given time. */
-void *decodeAVAudioStream(StreamPtr stream, size_t *length);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* ALFFMPEG_H */
diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h
index eda8925e..62ed5be2 100644
--- a/examples/common/alhelpers.h
+++ b/examples/common/alhelpers.h
@@ -9,6 +9,10 @@
#include <windows.h>
#endif
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
diff --git a/examples/common/sdl_sound.c b/examples/common/sdl_sound.c
new file mode 100644
index 00000000..79a5bf32
--- /dev/null
+++ b/examples/common/sdl_sound.c
@@ -0,0 +1,164 @@
+/*
+ * SDL_sound Decoder Helpers
+ *
+ * Copyright (c) 2013 by Chris Robinson <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This file contains routines for helping to decode audio using SDL_sound.
+ * There's very little OpenAL-specific code here.
+ */
+#include "sdl_sound.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <assert.h>
+
+#include <SDL_sound.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "alhelpers.h"
+
+
+static int done_init = 0;
+
+FilePtr openAudioFile(const char *fname, size_t buftime_ms)
+{
+ FilePtr file;
+ ALuint rate;
+ Uint32 bufsize;
+ ALenum chans, type;
+
+ /* We need to make sure SDL_sound is initialized. */
+ if(!done_init)
+ {
+ Sound_Init();
+ done_init = 1;
+ }
+
+ file = Sound_NewSampleFromFile(fname, NULL, 0);
+ if(!file)
+ {
+ fprintf(stderr, "Failed to open %s: %s\n", fname, Sound_GetError());
+ return NULL;
+ }
+
+ if(getAudioInfo(file, &rate, &chans, &type) != 0)
+ {
+ Sound_FreeSample(file);
+ return NULL;
+ }
+
+ bufsize = FramesToBytes((ALsizei)(buftime_ms/1000.0*rate), chans, type);
+ if(Sound_SetBufferSize(file, bufsize) == 0)
+ {
+ fprintf(stderr, "Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError());
+ Sound_FreeSample(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+void closeAudioFile(FilePtr file)
+{
+ if(file)
+ Sound_FreeSample(file);
+}
+
+
+int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type)
+{
+ if(file->actual.channels == 1)
+ *channels = AL_MONO_SOFT;
+ else if(file->actual.channels == 2)
+ *channels = AL_STEREO_SOFT;
+ else
+ {
+ fprintf(stderr, "Unsupported channel count: %d\n", file->actual.channels);
+ return 1;
+ }
+
+ if(file->actual.format == AUDIO_U8)
+ *type = AL_UNSIGNED_BYTE_SOFT;
+ else if(file->actual.format == AUDIO_S8)
+ *type = AL_BYTE_SOFT;
+ else if(file->actual.format == AUDIO_U16LSB || file->actual.format == AUDIO_U16MSB)
+ *type = AL_UNSIGNED_SHORT_SOFT;
+ else if(file->actual.format == AUDIO_S16LSB || file->actual.format == AUDIO_S16MSB)
+ *type = AL_SHORT_SOFT;
+ else
+ {
+ fprintf(stderr, "Unsupported sample format: 0x%04x\n", file->actual.format);
+ return 1;
+ }
+
+ *rate = file->actual.rate;
+
+ return 0;
+}
+
+
+uint8_t *getAudioData(FilePtr file, size_t *length)
+{
+ *length = Sound_Decode(file);
+ if(*length == 0)
+ return NULL;
+ if((file->actual.format == AUDIO_U16LSB && AUDIO_U16LSB != AUDIO_U16SYS) ||
+ (file->actual.format == AUDIO_U16MSB && AUDIO_U16MSB != AUDIO_U16SYS) ||
+ (file->actual.format == AUDIO_S16LSB && AUDIO_S16LSB != AUDIO_S16SYS) ||
+ (file->actual.format == AUDIO_S16MSB && AUDIO_S16MSB != AUDIO_S16SYS))
+ {
+ /* Swap bytes if the decoded endianness doesn't match the system. */
+ char *buffer = file->buffer;
+ size_t i;
+ for(i = 0;i < *length;i+=2)
+ {
+ char b = buffer[i];
+ buffer[i] = buffer[i+1];
+ buffer[i+1] = b;
+ }
+ }
+ return file->buffer;
+}
+
+void *decodeAudioStream(FilePtr file, size_t *length)
+{
+ Uint32 got;
+ char *mem;
+
+ got = Sound_DecodeAll(file);
+ if(got == 0)
+ {
+ *length = 0;
+ return NULL;
+ }
+
+ mem = malloc(got);
+ memcpy(mem, file->buffer, got);
+
+ *length = got;
+ return mem;
+}
diff --git a/examples/common/sdl_sound.h b/examples/common/sdl_sound.h
new file mode 100644
index 00000000..e93ab92b
--- /dev/null
+++ b/examples/common/sdl_sound.h
@@ -0,0 +1,43 @@
+#ifndef EXAMPLES_SDL_SOUND_H
+#define EXAMPLES_SDL_SOUND_H
+
+#include "AL/al.h"
+
+#include <SDL_sound.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Opaque handles to files and streams. Apps don't need to concern themselves
+ * with the internals */
+typedef Sound_Sample *FilePtr;
+
+/* Opens a file with SDL_sound, and specifies the size of the sample buffer in
+ * milliseconds. */
+FilePtr openAudioFile(const char *fname, size_t buftime_ms);
+
+/* Closes/frees an opened file */
+void closeAudioFile(FilePtr file);
+
+/* Returns information about the given audio stream. Returns 0 on success. */
+int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type);
+
+/* Returns a pointer to the next available chunk of decoded audio. The size (in
+ * bytes) of the returned data buffer is stored in 'length', and the returned
+ * pointer is only valid until the next call to getAudioData. */
+uint8_t *getAudioData(FilePtr file, size_t *length);
+
+/* Decodes all remaining data from the stream and returns a buffer containing
+ * the audio data, with the size stored in 'length'. The returned pointer must
+ * be freed with a call to free(). Note that since this decodes the whole
+ * stream, using it on lengthy streams (eg, music) will use a lot of memory.
+ * Such streams are better handled using getAudioData to keep smaller chunks in
+ * memory at any given time. */
+void *decodeAudioStream(FilePtr, size_t *length);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* EXAMPLES_SDL_SOUND_H */
diff --git a/include/AL/alext.h b/include/AL/alext.h
index 0447f2bb..f15ba33f 100644
--- a/include/AL/alext.h
+++ b/include/AL/alext.h
@@ -348,6 +348,22 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64
#endif
#endif
+#ifndef ALC_EXT_DEFAULT_FILTER_ORDER
+#define ALC_EXT_DEFAULT_FILTER_ORDER 1
+#define ALC_DEFAULT_FILTER_ORDER 0x1100
+#endif
+
+#ifndef AL_SOFT_deferred_updates
+#define AL_SOFT_deferred_updates 1
+#define AL_DEFERRED_UPDATES_SOFT 0xC002
+typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void);
+typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void);
+AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/utils/CIAIR.def b/utils/CIAIR.def
index 07fb1654..9589a694 100644
--- a/utils/CIAIR.def
+++ b/utils/CIAIR.def
@@ -1,7 +1,7 @@
# This is a makehrtf HRIR definition file. It is used to define the layout
# and source data to be processed into an OpenAL Soft compatible HRTF.
#
-# This definition is used to transform the left ear HRIRs from a dataset
+# This definition is used to transform the left ear HRIRs from a data set
# used in several papers and articles by Fumitada Itakura, Kazuya Takeda,
# Mikio Ikeda, Shoji Kajita, and Takanori Nishino.
#
diff --git a/utils/IRC_1005.def b/utils/IRC_1005.def
index 5c02c58a..f5a16934 100644
--- a/utils/IRC_1005.def
+++ b/utils/IRC_1005.def
@@ -2,9 +2,9 @@
# and source data to be processed into an OpenAL Soft compatible HRTF.
#
# This definition is used to transform an average of the left and right ear
-# HRIRs from any raw dataset from the IRCAM/AKG Listen HRTF database.
+# HRIRs from any raw data set from the IRCAM/AKG Listen HRTF database.
#
-# The datasets are available free of charge from:
+# The data sets are available free of charge from:
#
# http://recherche.ircam.fr/equipes/salles/listen/index.html
#
@@ -32,7 +32,7 @@ distance = 1.95
# The IRCAM source azimuth is counter-clockwise, so it needs to be flipped.
# Left and right ear HRIRs (from the respective WAVE channels) are averaged.
-# Repalce all occurrences of IRC_#### for the desired subject (1005 was used
+# Replace all occurrences of IRC_#### for the desired subject (1005 was used
# in this demonstration).
[ 3, 0 ] = wave (0) : "./IRC/RAW/WAV/IRC_1005_R/IRC_1005_R_R0195_T000_P315.wav"
diff --git a/utils/MIT_KEMAR.def b/utils/MIT_KEMAR.def
index 62412b2e..1067e0b4 100644
--- a/utils/MIT_KEMAR.def
+++ b/utils/MIT_KEMAR.def
@@ -5,17 +5,17 @@
# of KEMAR HRIRs provided by Bill Gardner <[email protected]> and Keith
# Martin <[email protected]> of MIT Media Laboratory.
#
-# The data (full.tar.Z or full.zip) is available from:
+# The data (full.zip) is available from:
#
# http://sound.media.mit.edu/resources/KEMAR.html
#
-# It is copyright 1994 by MIT Media Laboratory, and provided free of charge
+# It is copyrighted 1994 by MIT Media Laboratory, and provided free of charge
# with no restrictions on use so long as the authors (above) are cited.
#
# This definition is used to generate the internal HRTF table used by OpenAL
# Soft.
-# The following are the dataset metrics. They must always be specified at
+# The following are the data set metrics. They must always be specified at
# start of a definition file, but their order is not important.
# Sampling rate of the HRIR data (in hertz).
@@ -28,17 +28,21 @@ rate = 44100
points = 512
# A list of the number of azimuths measured for each elevation. There must
-# be at least 5 elevations covering the 180 degrees for the dataset to be
+# be at least 5 elevations covering the 180 degrees for the data set to be
# viable.
azimuths = 1, 12, 24, 36, 45, 56, 60, 72, 72, 72, 72, 72, 60, 56, 45, 36, 24, 12, 1
-# The approximate radius (measured ear-to-ear) of the listener's head (in
-# meters). This does not have to match the dataset, since makehrtf uses a
-# spherical model to reconstruct the propagation delay.
+# The radius of the listener's head (measured ear-to-ear in meters). The
+# makehrtf utility uses this value to rescale measured propagation delays
+# when a custom head radius is specified on the command line. It is also
+# used as the default radius when the spherical model is used to calculate an
+# approximate set of delays. This should match the data set as close as
+# possible for accurate rescaling when using the measured delays (the
+# default). At the moment, radius rescaling does not adjust HRIR coupling.
radius = 0.09
# The distance between the source and the listener (in meters). This does
-# have to match the dataset, but it's effect is minimal at the moment due to
+# have to match the data set, but it's effect is minimal at the moment due to
# the coupled nature of OpenAL Soft's HRTF model.
distance = 1.4
diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt
new file mode 100644
index 00000000..a6707a3d
--- /dev/null
+++ b/utils/alsoft-config/CMakeLists.txt
@@ -0,0 +1,29 @@
+project(alsoft-config)
+
+include_directories("${alsoft-config_BINARY_DIR}")
+
+# Need Qt 4.8.0 or newer for the iconset theme attribute to work
+find_package(Qt4 4.8.0 COMPONENTS QtCore QtGui)
+if(QT4_FOUND)
+ include(${QT_USE_FILE})
+
+ set(alsoft-config_SRCS main.cpp
+ mainwindow.cpp
+ )
+
+ set(alsoft-config_UIS mainwindow.ui)
+ QT4_WRAP_UI(UIS ${alsoft-config_UIS})
+
+ set(alsoft-config_MOCS mainwindow.h)
+ QT4_WRAP_CPP(MOCS ${alsoft-config_MOCS})
+
+ add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS})
+ target_link_libraries(alsoft-config ${QT_LIBRARIES})
+ set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR})
+
+ install(TARGETS alsoft-config
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+endif()
diff --git a/utils/alsoft-config/main.cpp b/utils/alsoft-config/main.cpp
new file mode 100644
index 00000000..b48f94ec
--- /dev/null
+++ b/utils/alsoft-config/main.cpp
@@ -0,0 +1,11 @@
+#include "mainwindow.h"
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp
new file mode 100644
index 00000000..0047233f
--- /dev/null
+++ b/utils/alsoft-config/mainwindow.cpp
@@ -0,0 +1,586 @@
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QSettings>
+#include <QtGlobal>
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+namespace {
+static const struct {
+ char backend_name[16];
+ char menu_string[32];
+} backendMenuList[] = {
+#ifdef Q_OS_WIN32
+ { "mmdevapi", "Add MMDevAPI" },
+ { "dsound", "Add DirectSound" },
+ { "winmm", "Add Windows Multimedia" },
+#endif
+#ifdef Q_OS_MAC
+ { "core", "Add CoreAudio" },
+#endif
+ { "pulse", "Add PulseAudio" },
+#ifdef Q_OS_UNIX
+ { "alsa", "Add ALSA" },
+ { "oss", "Add OSS" },
+ { "solaris", "Add Solaris" },
+ { "sndio", "Add SndIO" },
+ { "qsa", "Add QSA" },
+#endif
+ { "port", "Add PortAudio" },
+ { "opensl", "Add OpenSL" },
+ { "null", "Add Null Output" },
+ { "wave", "Add Wave Writer" },
+ { "", "" }
+};
+
+static QString getDefaultConfigName()
+{
+#ifdef Q_OS_WIN32
+ static const char fname[] = "alsoft.ini";
+ QByteArray base = qgetenv("AppData");
+#else
+ static const char fname[] = "alsoft.conf";
+ QByteArray base = qgetenv("XDG_CONFIG_HOME");
+ if(base.isEmpty())
+ {
+ base = qgetenv("HOME");
+ if(base.isEmpty() == false)
+ base += "/.config";
+ }
+#endif
+ if(base.isEmpty() == false)
+ return base +'/'+ fname;
+ return fname;
+}
+}
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow),
+ mPeriodSizeValidator(NULL),
+ mPeriodCountValidator(NULL),
+ mSourceCountValidator(NULL),
+ mEffectSlotValidator(NULL),
+ mSourceSendValidator(NULL),
+ mSampleRateValidator(NULL),
+ mReverbBoostValidator(NULL)
+{
+ ui->setupUi(this);
+
+ mPeriodSizeValidator = new QIntValidator(64, 8192, this);
+ ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
+ mPeriodCountValidator = new QIntValidator(2, 16, this);
+ ui->periodCountEdit->setValidator(mPeriodCountValidator);
+
+ mSourceCountValidator = new QIntValidator(0, 256, this);
+ ui->srcCountLineEdit->setValidator(mSourceCountValidator);
+ mEffectSlotValidator = new QIntValidator(0, 16, this);
+ ui->effectSlotLineEdit->setValidator(mEffectSlotValidator);
+ mSourceSendValidator = new QIntValidator(0, 4, this);
+ ui->srcSendLineEdit->setValidator(mSourceSendValidator);
+ mSampleRateValidator = new QIntValidator(8000, 192000, this);
+ ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
+
+ mReverbBoostValidator = new QDoubleValidator(-12.0, +12.0, 1, this);
+ ui->reverbBoostEdit->setValidator(mReverbBoostValidator);
+
+ connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile()));
+ connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile()));
+
+ connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig()));
+
+ connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int)));
+ connect(ui->periodSizeEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodSizeSlider()));
+ connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int)));
+ connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider()));
+
+ connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile()));
+ connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile()));
+ connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton()));
+
+ ui->enabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->enabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showEnabledBackendMenu(QPoint)));
+
+ ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint)));
+
+ connect(ui->reverbBoostSlider, SIGNAL(valueChanged(int)), this, SLOT(updateReverbBoostEdit(int)));
+ connect(ui->reverbBoostEdit, SIGNAL(textEdited(QString)), this, SLOT(updateReverbBoostSlider(QString)));
+
+ loadConfig(getDefaultConfigName());
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+ delete mPeriodSizeValidator;
+ delete mPeriodCountValidator;
+ delete mSourceCountValidator;
+ delete mEffectSlotValidator;
+ delete mSourceSendValidator;
+ delete mSampleRateValidator;
+ delete mReverbBoostValidator;
+}
+
+void MainWindow::loadConfigFromFile()
+{
+ QString fname = QFileDialog::getOpenFileName(this, tr("Select Files"));
+ if(fname.isEmpty() == false)
+ loadConfig(fname);
+}
+
+void MainWindow::loadConfig(const QString &fname)
+{
+ QSettings settings(fname, QSettings::IniFormat);
+
+ QString sampletype = settings.value("sample-type").toString();
+ ui->sampleFormatCombo->setCurrentIndex(0);
+ if(sampletype.isEmpty() == false)
+ {
+ for(int i = 1;i < ui->sampleFormatCombo->count();i++)
+ {
+ QString item = ui->sampleFormatCombo->itemText(i);
+ if(item.startsWith(sampletype))
+ {
+ ui->sampleFormatCombo->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ QString channelconfig = settings.value("channels").toString();
+ ui->channelConfigCombo->setCurrentIndex(0);
+ if(channelconfig.isEmpty() == false)
+ {
+ for(int i = 1;i < ui->channelConfigCombo->count();i++)
+ {
+ QString item = ui->channelConfigCombo->itemText(i);
+ if(item.startsWith(channelconfig))
+ {
+ ui->channelConfigCombo->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ QString srate = settings.value("frequency").toString();
+ if(srate.isEmpty())
+ ui->sampleRateCombo->setCurrentIndex(0);
+ else
+ {
+ ui->sampleRateCombo->lineEdit()->clear();
+ ui->sampleRateCombo->lineEdit()->insert(srate);
+ }
+
+ ui->srcCountLineEdit->clear();
+ ui->srcCountLineEdit->insert(settings.value("sources").toString());
+ ui->effectSlotLineEdit->clear();
+ ui->effectSlotLineEdit->insert(settings.value("slots").toString());
+ ui->srcSendLineEdit->clear();
+ ui->srcSendLineEdit->insert(settings.value("sends").toString());
+
+ QString resampler = settings.value("resampler").toString().trimmed();
+ if(resampler.isEmpty())
+ ui->resamplerComboBox->setCurrentIndex(0);
+ else
+ {
+ for(int i = 1;i < ui->resamplerComboBox->count();i++)
+ {
+ QString item = ui->resamplerComboBox->itemText(i);
+ int end = item.indexOf(' ');
+ if(end < 0) end = item.size();
+ if(resampler.size() == end && resampler.compare(item.leftRef(end), Qt::CaseInsensitive) == 0)
+ {
+ ui->resamplerComboBox->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ int periodsize = settings.value("period_size").toInt();
+ ui->periodSizeEdit->clear();
+ if(periodsize >= 64)
+ {
+ ui->periodSizeEdit->insert(QString::number(periodsize));
+ updatePeriodSizeSlider();
+ }
+
+ int periodcount = settings.value("periods").toInt();
+ ui->periodCountEdit->clear();
+ if(periodcount >= 2)
+ {
+ ui->periodCountEdit->insert(QString::number(periodcount));
+ updatePeriodCountSlider();
+ }
+
+ QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList();
+ if(disabledCpuExts.size() == 1)
+ disabledCpuExts = disabledCpuExts[0].split(QChar(','));
+ std::transform(disabledCpuExts.begin(), disabledCpuExts.end(),
+ disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed));
+ ui->disableSSECheckBox->setChecked(disabledCpuExts.contains("sse", Qt::CaseInsensitive));
+ ui->disableSSE2CheckBox->setChecked(disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
+ ui->disableNeonCheckBox->setChecked(disabledCpuExts.contains("neon", Qt::CaseInsensitive));
+
+ if(settings.value("hrtf").toString() == QString())
+ ui->hrtfEnableButton->setChecked(true);
+ else
+ {
+ if(settings.value("hrtf", true).toBool())
+ ui->hrtfForceButton->setChecked(true);
+ else
+ ui->hrtfDisableButton->setChecked(true);
+ }
+
+ QStringList hrtf_tables = settings.value("hrtf_tables").toStringList();
+ if(hrtf_tables.size() == 1)
+ hrtf_tables = hrtf_tables[0].split(QChar(','));
+ std::transform(hrtf_tables.begin(), hrtf_tables.end(),
+ hrtf_tables.begin(), std::mem_fun_ref(&QString::trimmed));
+ ui->hrtfFileList->clear();
+ ui->hrtfFileList->addItems(hrtf_tables);
+ updateHrtfRemoveButton();
+
+ ui->enabledBackendList->clear();
+ ui->disabledBackendList->clear();
+ QStringList drivers = settings.value("drivers").toStringList();
+ if(drivers.size() == 0)
+ ui->backendCheckBox->setChecked(true);
+ else
+ {
+ if(drivers.size() == 1)
+ drivers = drivers[0].split(QChar(','));
+ std::transform(drivers.begin(), drivers.end(),
+ drivers.begin(), std::mem_fun_ref(&QString::trimmed));
+
+ bool lastWasEmpty = false;
+ foreach(const QString &backend, drivers)
+ {
+ lastWasEmpty = backend.isEmpty();
+ if(!backend.startsWith(QChar('-')) && !lastWasEmpty)
+ ui->enabledBackendList->addItem(backend);
+ else if(backend.size() > 1)
+ ui->disabledBackendList->addItem(backend.right(backend.size()-1));
+ }
+ ui->backendCheckBox->setChecked(lastWasEmpty);
+ }
+
+ QString defaultreverb = settings.value("default-reverb").toString().toLower();
+ ui->defaultReverbComboBox->setCurrentIndex(0);
+ if(defaultreverb.isEmpty() == false)
+ {
+ for(int i = 0;i < ui->defaultReverbComboBox->count();i++)
+ {
+ if(defaultreverb.compare(ui->defaultReverbComboBox->itemText(i).toLower()) == 0)
+ {
+ ui->defaultReverbComboBox->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool());
+ ui->reverbBoostEdit->clear();
+ ui->reverbBoostEdit->insert(settings.value("reverb/boost").toString());
+
+ QStringList excludefx = settings.value("excludefx").toStringList();
+ if(excludefx.size() == 1)
+ excludefx = excludefx[0].split(QChar(','));
+ std::transform(excludefx.begin(), excludefx.end(),
+ excludefx.begin(), std::mem_fun_ref(&QString::trimmed));
+ ui->disableEaxReverbCheck->setChecked(excludefx.contains("eaxreverb", Qt::CaseInsensitive));
+ ui->disableStdReverbCheck->setChecked(excludefx.contains("reverb", Qt::CaseInsensitive));
+ ui->disableChorusCheck->setChecked(excludefx.contains("chorus", Qt::CaseInsensitive));
+ ui->disableDistortionCheck->setChecked(excludefx.contains("distortion", Qt::CaseInsensitive));
+ ui->disableEchoCheck->setChecked(excludefx.contains("echo", Qt::CaseInsensitive));
+ ui->disableEqualizerCheck->setChecked(excludefx.contains("equalizer", Qt::CaseInsensitive));
+ ui->disableFlangerCheck->setChecked(excludefx.contains("flanger", Qt::CaseInsensitive));
+ ui->disableModulatorCheck->setChecked(excludefx.contains("modulator", Qt::CaseInsensitive));
+ ui->disableDedicatedCheck->setChecked(excludefx.contains("dedicated", Qt::CaseInsensitive));
+}
+
+void MainWindow::saveCurrentConfig()
+{
+ saveConfig(getDefaultConfigName());
+ QMessageBox::information(this, tr("Information"),
+ tr("Applications using OpenAL need to be restarted for changes to take effect."));
+}
+
+void MainWindow::saveConfigAsFile()
+{
+ QString fname = QFileDialog::getOpenFileName(this, tr("Select Files"));
+ if(fname.isEmpty() == false)
+ saveConfig(fname);
+}
+
+void MainWindow::saveConfig(const QString &fname) const
+{
+ QSettings settings(fname, QSettings::IniFormat);
+
+ /* HACK: Compound any stringlist values into a comma-separated string. */
+ QStringList allkeys = settings.allKeys();
+ foreach(const QString &key, allkeys)
+ {
+ QStringList vals = settings.value(key).toStringList();
+ if(vals.size() > 1)
+ settings.setValue(key, vals.join(QChar(',')));
+ }
+
+ QString str = ui->sampleFormatCombo->currentText();
+ str.truncate(str.indexOf('-'));
+ settings.setValue("sample-type", str.trimmed());
+
+ str = ui->channelConfigCombo->currentText();
+ str.truncate(str.indexOf('-'));
+ settings.setValue("channels", str.trimmed());
+
+ uint rate = ui->sampleRateCombo->currentText().toUInt();
+ if(rate == 0)
+ settings.setValue("frequency", QString());
+ else
+ settings.setValue("frequency", rate);
+
+ settings.setValue("period_size", ui->periodSizeEdit->text());
+ settings.setValue("periods", ui->periodCountEdit->text());
+
+ settings.setValue("sources", ui->srcCountLineEdit->text());
+ settings.setValue("slots", ui->effectSlotLineEdit->text());
+
+ if(ui->resamplerComboBox->currentIndex() == 0)
+ settings.setValue("resampler", QString());
+ else
+ {
+ str = ui->resamplerComboBox->currentText();
+ settings.setValue("resampler", str.split(' ').first().toLower());
+ }
+
+ QStringList strlist;
+ if(ui->disableSSECheckBox->isChecked())
+ strlist.append("sse");
+ if(ui->disableSSE2CheckBox->isChecked())
+ strlist.append("sse2");
+ if(ui->disableNeonCheckBox->isChecked())
+ strlist.append("neon");
+ settings.setValue("disable-cpu-exts", strlist.join(QChar(',')));
+
+ if(ui->hrtfForceButton->isChecked())
+ settings.setValue("hrtf", "true");
+ else if(ui->hrtfDisableButton->isChecked())
+ settings.setValue("hrtf", "false");
+ else
+ settings.setValue("hrtf", QString());
+
+ strlist.clear();
+ QList<QListWidgetItem*> items = ui->hrtfFileList->findItems("*", Qt::MatchWildcard);
+ foreach(const QListWidgetItem *item, items)
+ strlist.append(item->text());
+ settings.setValue("hrtf_tables", strlist.join(QChar(',')));
+
+ strlist.clear();
+ items = ui->enabledBackendList->findItems("*", Qt::MatchWildcard);
+ foreach(const QListWidgetItem *item, items)
+ strlist.append(item->text());
+ items = ui->disabledBackendList->findItems("*", Qt::MatchWildcard);
+ foreach(const QListWidgetItem *item, items)
+ strlist.append(QChar('-')+item->text());
+ if(strlist.size() == 0 && !ui->backendCheckBox->isChecked())
+ strlist.append("-all");
+ else if(ui->backendCheckBox->isChecked())
+ strlist.append(QString());
+ settings.setValue("drivers", strlist.join(QChar(',')));
+
+ // TODO: Remove check when we can properly match global values.
+ if(ui->defaultReverbComboBox->currentIndex() == 0)
+ settings.setValue("default-reverb", QString());
+ else
+ {
+ str = ui->defaultReverbComboBox->currentText().toLower();
+ settings.setValue("default-reverb", str);
+ }
+
+ if(ui->emulateEaxCheckBox->isChecked())
+ settings.setValue("reverb/emulate-eax", "true");
+ else
+ settings.setValue("reverb/emulate-eax", QString()/*"false"*/);
+
+ // TODO: Remove check when we can properly match global values.
+ if(ui->reverbBoostSlider->sliderPosition() == 0)
+ settings.setValue("reverb/boost", QString());
+ else
+ settings.setValue("reverb/boost", ui->reverbBoostEdit->text());
+
+ strlist.clear();
+ if(ui->disableEaxReverbCheck->isChecked())
+ strlist.append("eaxreverb");
+ if(ui->disableStdReverbCheck->isChecked())
+ strlist.append("reverb");
+ if(ui->disableChorusCheck->isChecked())
+ strlist.append("chorus");
+ if(ui->disableDistortionCheck->isChecked())
+ strlist.append("distortion");
+ if(ui->disableEchoCheck->isChecked())
+ strlist.append("echo");
+ if(ui->disableEqualizerCheck->isChecked())
+ strlist.append("equalizer");
+ if(ui->disableFlangerCheck->isChecked())
+ strlist.append("flanger");
+ if(ui->disableModulatorCheck->isChecked())
+ strlist.append("modulator");
+ if(ui->disableDedicatedCheck->isChecked())
+ strlist.append("dedicated");
+ settings.setValue("excludefx", strlist.join(QChar(',')));
+
+ /* Remove empty keys
+ * FIXME: Should only remove keys whose value matches the globally-specified value.
+ */
+ allkeys = settings.allKeys();
+ foreach(const QString &key, allkeys)
+ {
+ str = settings.value(key).toString();
+ if(str == QString())
+ settings.remove(key);
+ }
+}
+
+
+void MainWindow::updatePeriodSizeEdit(int size)
+{
+ ui->periodSizeEdit->clear();
+ if(size >= 64)
+ {
+ size = (size+32)&~0x3f;
+ ui->periodSizeEdit->insert(QString::number(size));
+ }
+}
+
+void MainWindow::updatePeriodSizeSlider()
+{
+ int pos = ui->periodSizeEdit->text().toInt();
+ if(pos >= 64)
+ {
+ if(pos > 8192)
+ pos = 8192;
+ ui->periodSizeSlider->setSliderPosition(pos);
+ }
+}
+
+void MainWindow::updatePeriodCountEdit(int count)
+{
+ ui->periodCountEdit->clear();
+ if(count >= 2)
+ ui->periodCountEdit->insert(QString::number(count));
+}
+
+void MainWindow::updatePeriodCountSlider()
+{
+ int pos = ui->periodCountEdit->text().toInt();
+ if(pos < 2)
+ pos = 0;
+ else if(pos > 16)
+ pos = 16;
+ ui->periodCountSlider->setSliderPosition(pos);
+}
+
+
+void MainWindow::addHrtfFile()
+{
+ QStringList fnames = QFileDialog::getOpenFileNames(this, tr("Select Files"), QString(),
+ "HRTF Datasets(*.mhr);;All Files(*.*)");
+ if(fnames.isEmpty() == false)
+ ui->hrtfFileList->addItems(fnames);
+}
+
+void MainWindow::removeHrtfFile()
+{
+ QList<QListWidgetItem*> selected = ui->hrtfFileList->selectedItems();
+ foreach(QListWidgetItem *item, selected)
+ delete item;
+}
+
+void MainWindow::updateHrtfRemoveButton()
+{
+ ui->hrtfRemoveButton->setEnabled(ui->hrtfFileList->selectedItems().size() != 0);
+}
+
+void MainWindow::showEnabledBackendMenu(QPoint pt)
+{
+ QMap<QAction*,QString> actionMap;
+
+ pt = ui->enabledBackendList->mapToGlobal(pt);
+
+ QMenu ctxmenu;
+ QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove");
+ if(ui->enabledBackendList->selectedItems().size() == 0)
+ removeAction->setEnabled(false);
+ ctxmenu.addSeparator();
+ for(size_t i = 0;backendMenuList[i].backend_name[0];i++)
+ {
+ QAction *action = ctxmenu.addAction(backendMenuList[i].menu_string);
+ actionMap[action] = backendMenuList[i].backend_name;
+ if(ui->enabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0 ||
+ ui->disabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0)
+ action->setEnabled(false);
+ }
+
+ QAction *gotAction = ctxmenu.exec(pt);
+ if(gotAction == removeAction)
+ {
+ QList<QListWidgetItem*> selected = ui->enabledBackendList->selectedItems();
+ foreach(QListWidgetItem *item, selected)
+ delete item;
+ }
+ else if(gotAction != NULL)
+ {
+ QMap<QAction*,QString>::const_iterator iter = actionMap.find(gotAction);
+ if(iter != actionMap.end())
+ ui->enabledBackendList->addItem(iter.value());
+ }
+}
+
+void MainWindow::showDisabledBackendMenu(QPoint pt)
+{
+ QMap<QAction*,QString> actionMap;
+
+ pt = ui->disabledBackendList->mapToGlobal(pt);
+
+ QMenu ctxmenu;
+ QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove");
+ if(ui->disabledBackendList->selectedItems().size() == 0)
+ removeAction->setEnabled(false);
+ ctxmenu.addSeparator();
+ for(size_t i = 0;backendMenuList[i].backend_name[0];i++)
+ {
+ QAction *action = ctxmenu.addAction(backendMenuList[i].menu_string);
+ actionMap[action] = backendMenuList[i].backend_name;
+ if(ui->disabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0 ||
+ ui->enabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0)
+ action->setEnabled(false);
+ }
+
+ QAction *gotAction = ctxmenu.exec(pt);
+ if(gotAction == removeAction)
+ {
+ QList<QListWidgetItem*> selected = ui->disabledBackendList->selectedItems();
+ foreach(QListWidgetItem *item, selected)
+ delete item;
+ }
+ else if(gotAction != NULL)
+ {
+ QMap<QAction*,QString>::const_iterator iter = actionMap.find(gotAction);
+ if(iter != actionMap.end())
+ ui->disabledBackendList->addItem(iter.value());
+ }
+}
+
+void MainWindow::updateReverbBoostEdit(int value)
+{
+ ui->reverbBoostEdit->clear();
+ if(value != 0)
+ ui->reverbBoostEdit->insert(QString::number(value/10.0, 'f', 1));
+}
+
+void MainWindow::updateReverbBoostSlider(QString value)
+{
+ int pos = int(value.toFloat()*10.0f);
+ ui->reverbBoostSlider->setSliderPosition(pos);
+}
diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h
new file mode 100644
index 00000000..0421aabb
--- /dev/null
+++ b/utils/alsoft-config/mainwindow.h
@@ -0,0 +1,56 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QListWidget>
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private slots:
+ void saveCurrentConfig();
+
+ void saveConfigAsFile();
+ void loadConfigFromFile();
+
+ void updatePeriodSizeEdit(int size);
+ void updatePeriodSizeSlider();
+ void updatePeriodCountEdit(int size);
+ void updatePeriodCountSlider();
+
+ void addHrtfFile();
+ void removeHrtfFile();
+
+ void updateHrtfRemoveButton();
+
+ void showEnabledBackendMenu(QPoint pt);
+ void showDisabledBackendMenu(QPoint pt);
+
+ void updateReverbBoostEdit(int size);
+ void updateReverbBoostSlider(QString value);
+
+private:
+ Ui::MainWindow *ui;
+
+ QValidator *mPeriodSizeValidator;
+ QValidator *mPeriodCountValidator;
+ QValidator *mSourceCountValidator;
+ QValidator *mEffectSlotValidator;
+ QValidator *mSourceSendValidator;
+ QValidator *mSampleRateValidator;
+ QValidator *mReverbBoostValidator;
+
+ void loadConfig(const QString &fname);
+ void saveConfig(const QString &fname) const;
+};
+
+#endif // MAINWINDOW_H
diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui
new file mode 100644
index 00000000..4c7d0c69
--- /dev/null
+++ b/utils/alsoft-config/mainwindow.ui
@@ -0,0 +1,1397 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>564</width>
+ <height>454</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>OpenAL Soft Configuration</string>
+ </property>
+ <property name="windowIcon">
+ <iconset theme="preferences-desktop-sound">
+ <normaloff/>
+ </iconset>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <widget class="QPushButton" name="applyButton">
+ <property name="geometry">
+ <rect>
+ <x>470</x>
+ <y>405</y>
+ <width>81</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Apply</string>
+ </property>
+ <property name="icon">
+ <iconset theme="dialog-ok-apply">
+ <normaloff/>
+ </iconset>
+ </property>
+ </widget>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>0</y>
+ <width>541</width>
+ <height>401</height>
+ </rect>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_3">
+ <attribute name="title">
+ <string>Playback</string>
+ </attribute>
+ <widget class="QComboBox" name="sampleFormatCombo">
+ <property name="geometry">
+ <rect>
+ <x>120</x>
+ <y>20</y>
+ <width>206</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The output sample type. Currently, all mixing is done with 32-bit
+float and converted to the output sample type as needed.</string>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>- Autodetect -</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>int8 - signed 8-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>uint8 - unsigned 8-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>int16 - signed 16-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>uint16 - unsigned 16-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>int32 - signed 32-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>uint32 - unsigned 32-bit int</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>float32 - 32-bit float</string>
+ </property>
+ </item>
+ </widget>
+ <widget class="QLabel" name="label_5">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>101</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Sample Format:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_6">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>50</y>
+ <width>101</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Channels:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="channelConfigCombo">
+ <property name="geometry">
+ <rect>
+ <x>120</x>
+ <y>50</y>
+ <width>247</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The output channel configuration. Note that not all backends
+can properly detect the channel configuration and may default
+to stereo output.</string>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>- Autodetect -</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>mono - 1-channel Mono</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>stereo - 2-channel Stereo</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>quad - 4-channel Quadraphonic</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>surround51 - 5.1 Surround Sound</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>surround61 - 6.1 Surround Sound</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>surround71 - 7.1 Surround Sound</string>
+ </property>
+ </item>
+ </widget>
+ <widget class="QComboBox" name="sampleRateCombo">
+ <property name="geometry">
+ <rect>
+ <x>120</x>
+ <y>80</y>
+ <width>123</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The playback/mixing sample rate.</string>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="insertPolicy">
+ <enum>QComboBox::NoInsert</enum>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>- Autodetect -</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>96000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>48000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>44100</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>32000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>22050</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>16000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>11025</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8000</string>
+ </property>
+ </item>
+ </widget>
+ <widget class="QLabel" name="label_7">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>80</y>
+ <width>101</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Sample Rate:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>200</y>
+ <width>511</width>
+ <height>161</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>HRTF (Stereo only)</string>
+ </property>
+ <widget class="QRadioButton" name="hrtfEnableButton">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>30</y>
+ <width>71</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Allows applications to request HRTF mixing.</string>
+ </property>
+ <property name="text">
+ <string>Enable</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" name="hrtfDisableButton">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>50</y>
+ <width>71</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Does not allow HRTF mixing, even when requested.</string>
+ </property>
+ <property name="text">
+ <string>Disable</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" name="hrtfForceButton">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>70</y>
+ <width>71</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Attempts to force HRTF mixing, even if applications request not
+to do it. This may override the channel configuration and
+sample rate.</string>
+ </property>
+ <property name="text">
+ <string>Force</string>
+ </property>
+ </widget>
+ <widget class="QListWidget" name="hrtfFileList">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>30</y>
+ <width>361</width>
+ <height>121</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>A list of files containing HRTF data sets. The listed data sets
+are used in place of or in addiiton to the the built-in set. The
+filenames may contain these markers, which will be replaced
+as needed:
+%r - Device sampling rate
+%% - Percent sign (%)</string>
+ </property>
+ <property name="dragEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideNone</enum>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="hrtfAddButton">
+ <property name="geometry">
+ <rect>
+ <x>475</x>
+ <y>30</y>
+ <width>25</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset theme="list-add">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="hrtfRemoveButton">
+ <property name="geometry">
+ <rect>
+ <x>475</x>
+ <y>60</y>
+ <width>25</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset theme="list-remove">
+ <normaloff/>
+ </iconset>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>110</y>
+ <width>511</width>
+ <height>91</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Buffer Metrics</string>
+ </property>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>20</y>
+ <width>241</width>
+ <height>51</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The number of update periods. Higher values create a larger
+mix ahead, which helps protect against skips when the CPU is
+under load, but increases the delay between a sound getting
+mixed and being heard.</string>
+ </property>
+ <widget class="QLabel" name="label_11">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>0</y>
+ <width>201</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Period Count</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSlider" name="periodCountSlider">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>20</y>
+ <width>160</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>16</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>2</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ <property name="tracking">
+ <bool>true</bool>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="periodCountEdit">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>20</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="placeholderText">
+ <string>4</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="widget_2" native="true">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>241</width>
+ <height>51</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The update period size, in sample frames. This is the number of
+frames needed for each mixing update.</string>
+ </property>
+ <widget class="QSlider" name="periodSizeSlider">
+ <property name="geometry">
+ <rect>
+ <x>60</x>
+ <y>20</y>
+ <width>160</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>8192</number>
+ </property>
+ <property name="singleStep">
+ <number>64</number>
+ </property>
+ <property name="pageStep">
+ <number>1024</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ <property name="tracking">
+ <bool>true</bool>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval">
+ <number>512</number>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_10">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>0</y>
+ <width>201</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Period Samples</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="periodSizeEdit">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="placeholderText">
+ <string>1024</string>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Resources</string>
+ </attribute>
+ <widget class="QLineEdit" name="srcCountLineEdit">
+ <property name="geometry">
+ <rect>
+ <x>190</x>
+ <y>20</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The maximum number of allocatable sources. Lower values may
+help for systems with apps that try to play more sounds than
+the CPU can handle.</string>
+ </property>
+ <property name="inputMask">
+ <string/>
+ </property>
+ <property name="maxLength">
+ <number>3</number>
+ </property>
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ <property name="placeholderText">
+ <string>256</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>171</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Number of Sound Sources:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_4">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>50</y>
+ <width>171</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Number of Effect Slots:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="effectSlotLineEdit">
+ <property name="geometry">
+ <rect>
+ <x>190</x>
+ <y>50</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The maximum number of Auxiliary Effect Slots an app can
+create. A slot can use a non-negligible amount of CPU time if
+an effect is set on it even if no sources are feeding it, so this
+may help when apps use more than the system can handle.</string>
+ </property>
+ <property name="inputMask">
+ <string/>
+ </property>
+ <property name="maxLength">
+ <number>1</number>
+ </property>
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ <property name="placeholderText">
+ <string>4</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_8">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>80</y>
+ <width>171</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Number of Source Sends:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="srcSendLineEdit">
+ <property name="geometry">
+ <rect>
+ <x>190</x>
+ <y>80</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The number of auxiliary sends per source. When not specified,
+it allows the app to request how many it wants. The maximum
+value currently possible is 4.</string>
+ </property>
+ <property name="maxLength">
+ <number>1</number>
+ </property>
+ <property name="placeholderText">
+ <string>Auto</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_9">
+ <property name="geometry">
+ <rect>
+ <x>30</x>
+ <y>120</y>
+ <width>71</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Resampler:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="resamplerComboBox">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>120</y>
+ <width>203</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The resampling method used when mixing sources.</string>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>- Default -</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Point (low quality, fast)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Linear (basic quality, fast)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Cubic Spline (good quality)</string>
+ </property>
+ </item>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>150</y>
+ <width>511</width>
+ <height>61</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Disables use of specific CPU extensions. Certain methods may
+utilize CPU extensions when detected, and this is useful for
+preventing those extensions from being used.</string>
+ </property>
+ <property name="title">
+ <string>CPU Extensions</string>
+ </property>
+ <widget class="QCheckBox" name="disableSSECheckBox">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>101</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Disable SSE</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableSSE2CheckBox">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>20</y>
+ <width>111</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Disable SSE2</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableNeonCheckBox">
+ <property name="geometry">
+ <rect>
+ <x>380</x>
+ <y>20</y>
+ <width>111</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Disable Neon</string>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Backends</string>
+ </attribute>
+ <widget class="QCheckBox" name="backendCheckBox">
+ <property name="geometry">
+ <rect>
+ <x>170</x>
+ <y>200</y>
+ <width>161</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>When checked, allows all other available backends not listed in the priority or disabled lists.</string>
+ </property>
+ <property name="text">
+ <string>Allow Other Backends</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QListWidget" name="enabledBackendList">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>40</y>
+ <width>191</width>
+ <height>151</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>The backend driver list order. Unknown backends and
+duplicated names are ignored.</string>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>20</y>
+ <width>191</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Priority Backends:</string>
+ </property>
+ </widget>
+ <widget class="QListWidget" name="disabledBackendList">
+ <property name="geometry">
+ <rect>
+ <x>270</x>
+ <y>40</y>
+ <width>191</width>
+ <height>151</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Disabled backend driver list.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_2">
+ <property name="geometry">
+ <rect>
+ <x>270</x>
+ <y>20</y>
+ <width>191</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Disabled Backends:</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QWidget" name="tab_4">
+ <attribute name="title">
+ <string>Effects</string>
+ </attribute>
+ <widget class="QCheckBox" name="emulateEaxCheckBox">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>60</y>
+ <width>161</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Uses a simpler reverb method to emulate the EAX reverb
+effect. This may slightly improve performance at the cost of
+some quality.</string>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Emulate EAX Reverb:</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>100</y>
+ <width>511</width>
+ <height>61</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Global amplification for reverb output, expressed in decibels.
++6 will be a scale of (approximately) 2x, +12 will be a scale of
+4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
+value of 0 means no change.</string>
+ </property>
+ <property name="title">
+ <string>Reverb Boost</string>
+ </property>
+ <widget class="QSlider" name="reverbBoostSlider">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>391</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="minimum">
+ <number>-120</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ <property name="tickInterval">
+ <number>10</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="reverbBoostEdit">
+ <property name="geometry">
+ <rect>
+ <x>410</x>
+ <y>30</y>
+ <width>51</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string>0.0</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_12">
+ <property name="geometry">
+ <rect>
+ <x>460</x>
+ <y>30</y>
+ <width>31</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>dB</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_5">
+ <property name="geometry">
+ <rect>
+ <x>9</x>
+ <y>170</y>
+ <width>511</width>
+ <height>181</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Disables effects, preventing apps from recognizing them. This
+can help for apps that try to use effects which are too CPU
+intensive for the system to handle.</string>
+ </property>
+ <property name="title">
+ <string>Disabled Effects</string>
+ </property>
+ <widget class="QCheckBox" name="disableEaxReverbCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>30</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>EAX Reverb</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableStdReverbCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>60</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Standard Reverb</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableChorusCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>90</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Chorus</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableDistortionCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>120</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Distortion</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableEchoCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>150</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Echo</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableEqualizerCheck">
+ <property name="geometry">
+ <rect>
+ <x>320</x>
+ <y>30</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Equalizer</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableFlangerCheck">
+ <property name="geometry">
+ <rect>
+ <x>320</x>
+ <y>60</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Flanger</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableModulatorCheck">
+ <property name="geometry">
+ <rect>
+ <x>320</x>
+ <y>90</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Ring Modulator</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="disableDedicatedCheck">
+ <property name="geometry">
+ <rect>
+ <x>320</x>
+ <y>120</y>
+ <width>131</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Disables both the Dedicated Dialog and Dedicated LFE effects
+added by the ALC_EXT_DEDICATED extension.</string>
+ </property>
+ <property name="text">
+ <string>Dedicated ...</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QLabel" name="label_13">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>141</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Default Reverb Effect:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="defaultReverbComboBox">
+ <property name="geometry">
+ <rect>
+ <x>160</x>
+ <y>20</y>
+ <width>142</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Generic</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PaddedCell</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Room</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Bathroom</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Livingroom</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Stoneroom</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Auditorium</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>ConcertHall</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Cave</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Arena</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hangar</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CarpetedHallway</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hallway</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>StoneCorridor</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Alley</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Forest</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>City</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mountains</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Quarry</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Plain</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>ParkingLot</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>SewerPipe</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Underwater</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Drugged</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dizzy</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Psychotic</string>
+ </property>
+ </item>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>564</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="actionLoad"/>
+ <addaction name="actionSave_As"/>
+ <addaction name="separator"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <addaction name="menuFile"/>
+ </widget>
+ <action name="actionQuit">
+ <property name="icon">
+ <iconset theme="application-exit">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="text">
+ <string>&amp;Quit</string>
+ </property>
+ </action>
+ <action name="actionSave_As">
+ <property name="icon">
+ <iconset theme="document-save-as">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="text">
+ <string>Save &amp;As...</string>
+ </property>
+ <property name="toolTip">
+ <string>Save Configuration As</string>
+ </property>
+ </action>
+ <action name="actionLoad">
+ <property name="icon">
+ <iconset theme="document-open">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="text">
+ <string>&amp;Load...</string>
+ </property>
+ <property name="toolTip">
+ <string>Load Configuration File</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>actionQuit</sender>
+ <signal>activated()</signal>
+ <receiver>MainWindow</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>267</x>
+ <y>181</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+ <slots>
+ <slot>ShowHRTFContextMenu(QPoint)</slot>
+ </slots>
+</ui>
diff --git a/utils/makehrtf.c b/utils/makehrtf.c
index ea56ffcd..f9da9429 100644
--- a/utils/makehrtf.c
+++ b/utils/makehrtf.c
@@ -2,7 +2,7 @@
* HRTF utility for producing and demonstrating the process of creating an
* OpenAL Soft compatible HRIR data set.
*
- * Copyright (C) 2011-2012 Christopher Fitzgerald
+ * Copyright (C) 2011-2014 Christopher Fitzgerald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,7 +58,7 @@
* 1999
*/
-/* Needed for 64-bit unsigned integer. */
+// Needed for 64-bit unsigned integer.
#include "config.h"
#include <stdio.h>
@@ -153,6 +153,10 @@
#define MIN_TRUNCSIZE (8)
#define MAX_TRUNCSIZE (128)
+// The limits to the custom head radius on the command line.
+#define MIN_CUSTOM_RADIUS (0.05)
+#define MAX_CUSTOM_RADIUS (0.15)
+
// The truncation window size must be a multiple of the below value to allow
// for vectorized convolution.
#define MOD_TRUNCSIZE (8)
@@ -162,6 +166,8 @@
#define DEFAULT_SURFACE (1)
#define DEFAULT_LIMIT (24.0)
#define DEFAULT_TRUNCSIZE (32)
+#define DEFAULT_HEAD_MODEL (HM_DATASET)
+#define DEFAULT_CUSTOM_RADIUS (0.0)
// The four-character-codes for RIFF/RIFX WAVE file chunks.
#define FOURCC_RIFF (0x46464952) // 'RIFF'
@@ -208,6 +214,13 @@ enum ElementTypeT {
ET_FP // Floating-point elements.
};
+// Head model used for calculating the impulse delays.
+enum HeadModelT {
+ HM_NONE = 0,
+ HM_DATASET , // Measure the onset from the dataset.
+ HM_SPHERE // Calculate the onset using a spherical head model.
+};
+
// Desired output format from the command line.
enum OutputFormatT {
OF_NONE = 0,
@@ -239,6 +252,7 @@ typedef unsigned long long uint8;
typedef enum ByteOrderT ByteOrderT;
typedef enum SourceFormatT SourceFormatT;
typedef enum ElementTypeT ElementTypeT;
+typedef enum HeadModelT HeadModelT;
typedef enum OutputFormatT OutputFormatT;
typedef struct TokenReaderT TokenReaderT;
@@ -724,8 +738,8 @@ static int StrSubst (const char * in, const char * pat, const char * rep, const
return (! truncated);
}
-// Provide missing math routines for MSVC.
-#ifdef _MSC_VER
+// Provide missing math routines for MSVC versions < 1800 (Visual Studio 2013).
+#if defined(_MSC_VER) && _MSC_VER < 1800
static double round (double val) {
if (val < 0.0)
return (ceil (val - 0.5));
@@ -1683,6 +1697,25 @@ static int LoadSource (SourceRefT * src, const uint hrirRate, const uint n, doub
return (result);
}
+// Calculate the onset time of an HRIR and average it with any existing
+// timing for its elevation and azimuth.
+static void AverageHrirOnset (const double * hrir, const double f, const uint ei, const uint ai, const HrirDataT * hData) {
+ double mag;
+ uint n, i, j;
+
+ mag = 0.0;
+ n = hData -> mIrPoints;
+ for (i = 0; i < n; i ++)
+ mag = fmax (fabs (hrir [i]), mag);
+ mag *= 0.15;
+ for (i = 0; i < n; i ++) {
+ if (fabs (hrir [i]) >= mag)
+ break;
+ }
+ j = hData -> mEvOffset [ei] + ai;
+ hData -> mHrtds [j] = Lerp (hData -> mHrtds [j], ((double) i) / hData -> mIrRate, f);
+}
+
// Calculate the magnitude response of an HRIR and average it with any
// existing responses for its elevation and azimuth.
static void AverageHrirMagnitude (const double * hrir, const double f, const uint ei, const uint ai, const HrirDataT * hData) {
@@ -1867,6 +1900,26 @@ static void CalcAzIndices (const HrirDataT * hData, const uint ei, const double
(* jf) = af;
}
+// Synthesize any missing onset timings at the bottom elevations. This just
+// blends between slightly exaggerated known onsets. Not an accurate model.
+static void SynthesizeOnsets (HrirDataT * hData) {
+ uint oi, e, a, j0, j1;
+ double t, of, jf;
+
+ oi = hData -> mEvStart;
+ t = 0.0;
+ for (a = 0; a < hData -> mAzCount [oi]; a ++)
+ t += hData -> mHrtds [hData -> mEvOffset [oi] + a];
+ hData -> mHrtds [0] = 1.32e-4 + (t / hData -> mAzCount [oi]);
+ for (e = 1; e < hData -> mEvStart; e ++) {
+ of = ((double) e) / hData -> mEvStart;
+ for (a = 0; a < hData -> mAzCount [e]; a ++) {
+ CalcAzIndices (hData, oi, a * 2.0 * M_PI / hData -> mAzCount [e], & j0, & j1, & jf);
+ hData -> mHrtds [hData -> mEvOffset [e] + a] = Lerp (hData -> mHrtds [0], Lerp (hData -> mHrtds [j0], hData -> mHrtds [j1], jf), of);
+ }
+ }
+}
+
/* Attempt to synthesize any missing HRIRs at the bottom elevations. Right
* now this just blends the lowest elevation HRIRs together and applies some
* attenuation and high frequency damping. It is a simple, if inaccurate
@@ -1966,9 +2019,9 @@ static double CalcLTD (const double ev, const double az, const double rad, const
return (dlp / 343.3);
}
-// Calculate the effective head-related time delays for the each HRIR, now
-// that they are minimum-phase.
-static void CalculateHrtds (HrirDataT * hData) {
+// Calculate the effective head-related time delays for each minimum-phase
+// HRIR.
+static void CalculateHrtds (const HeadModelT model, const double radius, HrirDataT * hData) {
double minHrtd, maxHrtd;
uint e, a, j;
double t;
@@ -1978,9 +2031,13 @@ static void CalculateHrtds (HrirDataT * hData) {
for (e = 0; e < hData -> mEvCount; e ++) {
for (a = 0; a < hData -> mAzCount [e]; a ++) {
j = hData -> mEvOffset [e] + a;
- t = CalcLTD ((-90.0 + (e * 180.0 / (hData -> mEvCount - 1))) * M_PI / 180.0,
- (a * 360.0 / hData -> mAzCount [e]) * M_PI / 180.0,
- hData -> mRadius, hData -> mDistance);
+ if (model == HM_DATASET) {
+ t = hData -> mHrtds [j] * radius / hData -> mRadius;
+ } else {
+ t = CalcLTD ((-90.0 + (e * 180.0 / (hData -> mEvCount - 1))) * M_PI / 180.0,
+ (a * 360.0 / hData -> mAzCount [e]) * M_PI / 180.0,
+ radius, hData -> mDistance);
+ }
hData -> mHrtds [j] = t;
maxHrtd = fmax (t, maxHrtd);
minHrtd = fmin (t, minHrtd);
@@ -2372,7 +2429,7 @@ static int ReadSourceRef (TokenReaderT * tr, SourceRefT * src) {
}
// Process the list of sources in the data set definition.
-static int ProcessSources (TokenReaderT * tr, HrirDataT * hData) {
+static int ProcessSources (const HeadModelT model, TokenReaderT * tr, HrirDataT * hData) {
uint * setCount = NULL, * setFlag = NULL;
double * hrir = NULL;
uint line, col, ei, ai;
@@ -2393,6 +2450,8 @@ static int ProcessSources (TokenReaderT * tr, HrirDataT * hData) {
for (;;) {
if (ReadSourceRef (tr, & src)) {
if (LoadSource (& src, hData -> mIrRate, hData -> mIrPoints, hrir)) {
+ if (model == HM_DATASET)
+ AverageHrirOnset (hrir, 1.0 / factor, ei, ai, hData);
AverageHrirMagnitude (hrir, 1.0 / factor, ei, ai, hData);
factor += 1.0;
if (! TrIsOperator (tr, "+"))
@@ -2452,7 +2511,7 @@ static int ProcessSources (TokenReaderT * tr, HrirDataT * hData) {
* resulting data set as desired. If the input name is NULL it will read
* from standard input.
*/
-static int ProcessDefinition (const char * inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const OutputFormatT outFormat, const char * outName) {
+static int ProcessDefinition (const char * inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const OutputFormatT outFormat, const char * outName) {
FILE * fp = NULL;
TokenReaderT tr;
HrirDataT hData;
@@ -2486,7 +2545,7 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin
}
hData . mHrirs = CreateArray (hData . mIrCount * hData . mIrSize);
hData . mHrtds = CreateArray (hData . mIrCount);
- if (! ProcessSources (& tr, & hData)) {
+ if (! ProcessSources (model, & tr, & hData)) {
DestroyArray (hData . mHrtds);
DestroyArray (hData . mHrirs);
if (inName != NULL)
@@ -2512,11 +2571,13 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin
fprintf (stdout, "Truncating minimum-phase HRIRs...\n");
hData . mIrPoints = truncSize;
fprintf (stdout, "Synthesizing missing elevations...\n");
+ if (model == HM_DATASET)
+ SynthesizeOnsets (& hData);
SynthesizeHrirs (& hData);
fprintf (stdout, "Normalizing final HRIRs...\n");
NormalizeHrirs (& hData);
fprintf (stdout, "Calculating impulse delays...\n");
- CalculateHrtds (& hData);
+ CalculateHrtds (model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData . mRadius, & hData);
snprintf (rateStr, 8, "%u", hData . mIrRate);
StrSubst (outName, "%r", rateStr, MAX_PATH_LEN, expName);
switch (outFormat) {
@@ -2547,6 +2608,8 @@ int main (const int argc, const char * argv []) {
int equalize, surface;
double limit;
uint truncSize;
+ HeadModelT model;
+ double radius;
char * end = NULL;
if (argc < 2) {
@@ -2573,6 +2636,9 @@ int main (const int argc, const char * argv []) {
fprintf (stdout, " average (default: %.2f).\n", DEFAULT_LIMIT);
fprintf (stdout, " -w=<points> Specify the size of the truncation window that's applied\n");
fprintf (stdout, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE);
+ fprintf (stdout, " -d={dataset| Specify the model used for calculating the head-delay timing\n");
+ fprintf (stdout, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere"));
+ fprintf (stdout, " -c=<size> Use a customized head radius measured ear-to-ear in meters.\n");
fprintf (stdout, " -i=<filename> Specify an HRIR definition file to use (defaults to stdin).\n");
fprintf (stdout, " -o=<filename> Specify an output file. Overrides command-selected default.\n");
fprintf (stdout, " Use of '%%r' will be substituted with the data set sample rate.\n");
@@ -2601,6 +2667,8 @@ int main (const int argc, const char * argv []) {
surface = DEFAULT_SURFACE;
limit = DEFAULT_LIMIT;
truncSize = DEFAULT_TRUNCSIZE;
+ model = DEFAULT_HEAD_MODEL;
+ radius = DEFAULT_CUSTOM_RADIUS;
while (argi < argc) {
if (strncmp (argv [argi], "-r=", 3) == 0) {
outRate = strtoul (& argv [argi] [3], & end, 10);
@@ -2648,6 +2716,21 @@ int main (const int argc, const char * argv []) {
fprintf (stderr, "Error: Expected a value from %u to %u in multiples of %u for '-w'.\n", MIN_TRUNCSIZE, MAX_TRUNCSIZE, MOD_TRUNCSIZE);
return (-1);
}
+ } else if (strncmp (argv [argi], "-d=", 3) == 0) {
+ if (strcmp (& argv [argi] [3], "dataset") == 0) {
+ model = HM_DATASET;
+ } else if (strcmp (& argv [argi] [3], "sphere") == 0) {
+ model = HM_SPHERE;
+ } else {
+ fprintf (stderr, "Error: Expected 'dataset' or 'sphere' for '-d'.\n");
+ return (-1);
+ }
+ } else if (strncmp (argv [argi], "-c=", 3) == 0) {
+ radius = strtod (& argv [argi] [3], & end);
+ if ((end [0] != '\0') || (radius < MIN_CUSTOM_RADIUS) || (radius > MAX_CUSTOM_RADIUS)) {
+ fprintf (stderr, "Error: Expected a value from %.2f to %.2f for '-c'.\n", MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS);
+ return (-1);
+ }
} else if (strncmp (argv [argi], "-i=", 3) == 0) {
inName = & argv [argi] [3];
} else if (strncmp (argv [argi], "-o=", 3) == 0) {
@@ -2658,7 +2741,7 @@ int main (const int argc, const char * argv []) {
}
argi ++;
}
- if (! ProcessDefinition (inName, outRate, fftSize, equalize, surface, limit, truncSize, outFormat, outName))
+ if (! ProcessDefinition (inName, outRate, fftSize, equalize, surface, limit, truncSize, model, radius, outFormat, outName))
return (-1);
fprintf (stdout, "Operation completed.\n");
return (0);