diff options
author | Sven Gothel <[email protected]> | 2014-01-26 07:06:02 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-01-26 07:06:02 +0100 |
commit | e6f4251945c228a775649b5ccd7f11dd4519c28d (patch) | |
tree | 8454b34363358cf9bb502021a68c6985c97daac4 | |
parent | 389ae1f767bfad6116e21306fc3cdf89a4cbcc0a (diff) | |
parent | 49baa9128dd98e986639def4f24c7522d9ec6b56 (diff) |
Merge branch 'UPSTREAM'
105 files changed, 20368 insertions, 7741 deletions
@@ -1,5 +1,6 @@ build winbuild +win64build include/sndio.h include/sys openal-soft.kdev4 @@ -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); +} @@ -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, ¶m); + param.sched_priority=param.sched_curpriority+1; + SchedSet(0, 0, SCHED_NOCHANGE, ¶m); + + 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) @@ -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>&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>&Quit</string> + </property> + </action> + <action name="actionSave_As"> + <property name="icon"> + <iconset theme="document-save-as"> + <normaloff/> + </iconset> + </property> + <property name="text"> + <string>Save &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>&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); |